diff options
Diffstat (limited to 'apps')
61 files changed, 5110 insertions, 1620 deletions
diff --git a/apps/user_ldap/ajax/getNewServerConfigPrefix.php b/apps/user_ldap/ajax/getNewServerConfigPrefix.php index 7d1434a8fb4..d0135917886 100644 --- a/apps/user_ldap/ajax/getNewServerConfigPrefix.php +++ b/apps/user_ldap/ajax/getNewServerConfigPrefix.php @@ -32,4 +32,17 @@ sort($serverConnections); $lk = array_pop($serverConnections); $ln = intval(str_replace('s', '', $lk)); $nk = 's'.str_pad($ln+1, 2, '0', STR_PAD_LEFT); -OCP\JSON::success(array('configPrefix' => $nk)); + +$resultData = array('configPrefix' => $nk); + +if(isset($_POST['copyConfig'])) { + $originalConfig = new \OCA\user_ldap\lib\Configuration($_POST['copyConfig']); + $newConfig = new \OCA\user_ldap\lib\Configuration($nk, false); + $newConfig->setConfiguration($originalConfig->getConfiguration()); + $newConfig->saveConfiguration(); +} else { + $configuration = new \OCA\user_ldap\lib\Configuration($nk, false); + $resultData['defaults'] = $configuration->getDefaults(); +} + +OCP\JSON::success($resultData); diff --git a/apps/user_ldap/ajax/wizard.php b/apps/user_ldap/ajax/wizard.php index ab521b5bf0e..267b9568a28 100644 --- a/apps/user_ldap/ajax/wizard.php +++ b/apps/user_ldap/ajax/wizard.php @@ -72,13 +72,11 @@ switch($action) { case 'determineGroupsForGroups': case 'determineAttributes': case 'getUserListFilter': - case 'getLoginFilterMode': case 'getUserLoginFilter': - case 'getUserFilterMode': case 'getGroupFilter': - case 'getGroupFilterMode': case 'countUsers': case 'countGroups': + case 'countInBaseDN': try { $result = $wizard->$action(); if($result !== false) { @@ -93,6 +91,23 @@ switch($action) { exit; break; + case 'testLoginName': { + try { + $loginName = $_POST['ldap_test_loginname']; + $result = $wizard->$action($loginName); + if($result !== false) { + OCP\JSON::success($result->getResultArray()); + exit; + } + } catch (\Exception $e) { + \OCP\JSON::error(array('message' => $e->getMessage())); + exit; + } + \OCP\JSON::error(); + exit; + break; + } + case 'save': $key = isset($_POST['cfgkey']) ? $_POST['cfgkey'] : false; $val = isset($_POST['cfgval']) ? $_POST['cfgval'] : null; @@ -115,6 +130,6 @@ switch($action) { OCP\JSON::success(); break; default: - //TODO: return 4xx error + \OCP\JSON::error(array('message' => $l->t('Action does not exist'))); break; } diff --git a/apps/user_ldap/appinfo/version b/apps/user_ldap/appinfo/version index 8f0916f768f..a918a2aa18d 100644 --- a/apps/user_ldap/appinfo/version +++ b/apps/user_ldap/appinfo/version @@ -1 +1 @@ -0.5.0 +0.6.0 diff --git a/apps/user_ldap/css/settings.css b/apps/user_ldap/css/settings.css index 8f339451c64..b351f9ae2af 100644 --- a/apps/user_ldap/css/settings.css +++ b/apps/user_ldap/css/settings.css @@ -1,6 +1,6 @@ .table { display: table; - width: 60%; + width: 85%; } .tablerow { @@ -21,10 +21,18 @@ margin-left: 3px; } +.ldapIconCopy { + background-image: url('../img/copy.svg'); +} + .invisible { visibility: hidden; } +.forceHidden { + display: none !important; +} + .ldapSettingsTabs { float: right !important; } @@ -49,13 +57,16 @@ } #ldapWizard1 .hostPortCombinator div span { - width: 7%; - display: table-cell; + width: 14.5%; + display: inline-block; text-align: right; } #ldapWizard1 .host { - width: 96.5% !important; + width: 100%; + margin-left: 0; + margin-right: 0; + border: 0; } .tableCellInput { @@ -77,7 +88,7 @@ color: #FF3B3B; } -.wizSpinner { +.ldapSpinner { height: 15px; margin: 5px; } @@ -104,10 +115,51 @@ width: auto; } +.ldapManyGroupsSupport span { + display: inline-block; + vertical-align: top; + height: 150px; +} + +.ldapManyGroupsSupport span button { + margin-top: 35px; +} + +.ldapManyGroupsSearch { + width: 425px !important; +} + +.ldapGroupList { + height: 150px; + width: 200px; +} + #ldap fieldset input, #ldap fieldset textarea { width: 60%; } +#ldap fieldset textarea ~ button { + vertical-align: text-bottom; +} + +input.ldapVerifyInput { + width: 150px !important; +} + +.ldapInputColElement { + width: 35%; + display: inline-block; + padding-left: 10px; +} + +.ldapToggle { + text-decoration: underline; +} + +span.ldapInputColElement { + margin-top: 9px; +} + #ldap fieldset p input[type=checkbox] { vertical-align: bottom; } diff --git a/apps/user_ldap/img/copy.png b/apps/user_ldap/img/copy.png Binary files differnew file mode 100644 index 00000000000..283d627a5a7 --- /dev/null +++ b/apps/user_ldap/img/copy.png diff --git a/apps/user_ldap/img/copy.svg b/apps/user_ldap/img/copy.svg new file mode 100644 index 00000000000..2e19d8066e3 --- /dev/null +++ b/apps/user_ldap/img/copy.svg @@ -0,0 +1,120 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns="http://www.w3.org/2000/svg" + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:ns1="http://sozi.baierouge.fr" + xmlns:cc="http://web.resource.org/cc/" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + id="svg1" + sodipodi:docname="copy.svg" + viewBox="0 0 60 60" + sodipodi:version="0.32" + _SVGFile__filename="oldscale/actions/copy.svg" + version="1.0" + y="0" + x="0" + inkscape:version="0.40" + sodipodi:docbase="/home/danny/work/flat/SVG/mono/scalable/actions" + > + <sodipodi:namedview + id="base" + bordercolor="#666666" + inkscape:pageshadow="2" + inkscape:window-y="0" + pagecolor="#ffffff" + inkscape:window-height="699" + inkscape:zoom="4.9119411" + inkscape:window-x="0" + borderopacity="1.0" + inkscape:current-layer="svg1" + inkscape:cx="60.290892" + inkscape:cy="24.030855" + inkscape:window-width="1024" + inkscape:pageopacity="0.0" + /> + <path + id="path1716" + style="stroke-linejoin:round;stroke:#ffffff;stroke-width:8.3605;fill:none" + transform="matrix(.97183 0 0 .97183 .87037 .23733)" + d="m7.513 4.5767c-1.3709 0-2.4745 1.1036-2.4745 2.4745v31.564c0 1.371 1.1036 2.474 2.4745 2.474h29.783c1.371 0 2.474-1.103 2.474-2.474v-31.564c0-1.3707-1.103-2.4743-2.474-2.4743h-29.783z" + /> + <path + id="rect1101" + style="stroke-linejoin:round;fill-rule:evenodd;stroke:#000000;stroke-width:3.2156;fill:#ffffff" + transform="matrix(.97183 0 0 .97183 .87037 .23733)" + d="m7.513 4.5767c-1.3709 0-2.4745 1.1036-2.4745 2.4745v31.564c0 1.371 1.1036 2.474 2.4745 2.474h29.783c1.371 0 2.474-1.103 2.474-2.474v-31.564c0-1.3707-1.103-2.4743-2.474-2.4743h-29.783z" + /> + <path + id="path1094" + style="stroke-linejoin:round;stroke:#ffffff;stroke-width:8.3605;fill:none" + transform="matrix(.97183 0 0 .97183 .87037 .23733)" + d="m22.652 20.161c-1.37 0-2.474 1.104-2.474 2.475v31.564c0 1.371 1.104 2.474 2.474 2.474h29.783c1.371 0 2.475-1.103 2.475-2.474v-31.564c0-1.371-1.104-2.475-2.475-2.475h-29.783z" + /> + <path + id="rect1111" + style="stroke-linejoin:round;fill-rule:evenodd;stroke:#000000;stroke-width:3.2156;fill:#ffffff" + transform="matrix(.97183 0 0 .97183 .87037 .23733)" + d="m22.652 20.161c-1.37 0-2.474 1.104-2.474 2.475v31.564c0 1.371 1.104 2.474 2.474 2.474h29.783c1.371 0 2.475-1.103 2.475-2.474v-31.564c0-1.371-1.104-2.475-2.475-2.475h-29.783z" + /> + <path + id="path1718" + style="stroke-linejoin:round;stroke:#ffffff;stroke-linecap:round;stroke-width:8.125;fill:none" + d="m12.457 21.599c2.325 20.529 20.15 19.15 21.296 19.043v6.139l8.981-8.889-8.981-8.87v6.066c-1.348 0.159-13.941 1.422-21.296-13.489z" + /> + <path + id="path1574" + style="stroke-linejoin:round;fill-rule:evenodd;stroke:#000000;stroke-linecap:round;stroke-width:3.125;fill:#000000" + d="m12.457 21.599c2.325 20.529 20.15 19.15 21.296 19.043v6.139l8.981-8.889-8.981-8.87v6.066c-1.348 0.159-13.941 1.422-21.296-13.489z" + /> + <metadata + > + <rdf:RDF + > + <cc:Work + > + <dc:format + >image/svg+xml</dc:format + > + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" + /> + <cc:license + rdf:resource="http://creativecommons.org/licenses/publicdomain/" + /> + <dc:publisher + > + <cc:Agent + rdf:about="http://openclipart.org/" + > + <dc:title + >Openclipart</dc:title + > + </cc:Agent + > + </dc:publisher + > + </cc:Work + > + <cc:License + rdf:about="http://creativecommons.org/licenses/publicdomain/" + > + <cc:permits + rdf:resource="http://creativecommons.org/ns#Reproduction" + /> + <cc:permits + rdf:resource="http://creativecommons.org/ns#Distribution" + /> + <cc:permits + rdf:resource="http://creativecommons.org/ns#DerivativeWorks" + /> + </cc:License + > + </rdf:RDF + > + </metadata + > +</svg +> diff --git a/apps/user_ldap/js/experiencedAdmin.js b/apps/user_ldap/js/experiencedAdmin.js deleted file mode 100644 index 7dc5a4e503d..00000000000 --- a/apps/user_ldap/js/experiencedAdmin.js +++ /dev/null @@ -1,92 +0,0 @@ -/** - * Copyright (c) 2014, Arthur Schiwon <blizzz@owncloud.com> - * This file is licensed under the Affero General Public License version 3 or later. - * See the COPYING-README file. - */ - -/* global LdapWizard */ - -/** - * controls behaviour depend on whether the admin is experienced in LDAP or not. - * - * @class - * @param {object} wizard the LDAP Wizard object - * @param {boolean} initialState whether the admin is experienced or not - */ -function ExperiencedAdmin(wizard, initialState) { - this.wizard = wizard; - this._isExperienced = initialState; - if(this._isExperienced) { - this.hideEntryCounters(); - } -} - - -/** - * toggles whether the admin is an experienced one or not - * - * @param {boolean} isExperienced whether the admin is experienced or not - */ -ExperiencedAdmin.prototype.setExperienced = function(isExperienced) { - this._isExperienced = isExperienced; - if(this._isExperienced) { - this.enableRawMode(); - this.hideEntryCounters(); - } else { - this.showEntryCounters(); - } -}; - -/** -* answers whether the admin is an experienced one or not -* -* @return {boolean} whether the admin is experienced or not -*/ -ExperiencedAdmin.prototype.isExperienced = function() { - return this._isExperienced; -}; - -/** - * switches all LDAP filters from Assisted to Raw mode. - */ -ExperiencedAdmin.prototype.enableRawMode = function() { - LdapWizard._save({id: 'ldapGroupFilterMode'}, LdapWizard.filterModeRaw); - LdapWizard._save({id: 'ldapUserFilterMode' }, LdapWizard.filterModeRaw); - LdapWizard._save({id: 'ldapLoginFilterMode'}, LdapWizard.filterModeRaw); -}; - -ExperiencedAdmin.prototype.updateUserTab = function(mode) { - this._updateTab(mode, $('#ldap_user_count')); -}; - -ExperiencedAdmin.prototype.updateGroupTab = function(mode) { - this._updateTab(mode, $('#ldap_group_count')); -}; - -ExperiencedAdmin.prototype._updateTab = function(mode, $countEl) { - if(mode === LdapWizard.filterModeAssisted) { - $countEl.removeClass('hidden'); - } else if(!this._isExperienced) { - $countEl.removeClass('hidden'); - } else { - $countEl.addClass('hidden'); - } -}; - -/** - * hide user and group counters, they will be displayed on demand only - */ -ExperiencedAdmin.prototype.hideEntryCounters = function() { - $('#ldap_user_count').addClass('hidden'); - $('#ldap_group_count').addClass('hidden'); - $('.ldapGetEntryCount').removeClass('hidden'); -}; - -/** -* shows user and group counters, they will be displayed on demand only -*/ -ExperiencedAdmin.prototype.showEntryCounters = function() { - $('#ldap_user_count').removeClass('hidden'); - $('#ldap_group_count').removeClass('hidden'); - $('.ldapGetEntryCount').addClass('hidden'); -}; diff --git a/apps/user_ldap/js/ldapFilter.js b/apps/user_ldap/js/ldapFilter.js deleted file mode 100644 index dc65858217d..00000000000 --- a/apps/user_ldap/js/ldapFilter.js +++ /dev/null @@ -1,193 +0,0 @@ -/* global LdapWizard */ - -function LdapFilter(target, determineModeCallback) { - this.locked = true; - this.target = false; - this.mode = LdapWizard.filterModeAssisted; - this.lazyRunCompose = false; - this.determineModeCallback = determineModeCallback; - this.foundFeatures = false; - this.activated = false; - this.countPending = false; - - if( target === 'User' || - target === 'Login' || - target === 'Group') { - this.target = target; - } -} - -LdapFilter.prototype.activate = function() { - if(this.activated) { - // might be necessary, if configuration changes happened. - this.findFeatures(); - return; - } - this.activated = true; - - this.determineMode(); -}; - -LdapFilter.prototype.compose = function(updateCount) { - var action; - - if(updateCount === true) { - this.countPending = updateCount; - } - - if(this.locked) { - this.lazyRunCompose = true; - return false; - } - - if(this.mode === LdapWizard.filterModeRaw) { - //Raw filter editing, i.e. user defined filter, don't compose - return; - } - - if(this.target === 'User') { - action = 'getUserListFilter'; - } else if(this.target === 'Login') { - action = 'getUserLoginFilter'; - } else if(this.target === 'Group') { - action = 'getGroupFilter'; - } - - var param = 'action='+action+ - '&ldap_serverconfig_chooser='+ - encodeURIComponent($('#ldap_serverconfig_chooser').val()); - - var filter = this; - - LdapWizard.ajax(param, - function(result) { - filter.afterComposeSuccess(result); - }, - function () { - filter.countPending = false; - console.log('LDAP Wizard: could not compose filter. '+ - 'Please check owncloud.log'); - } - ); -}; - -/** - * this function is triggered after LDAP filters have been composed successfully - * @param {object} result returned by the ajax call - */ -LdapFilter.prototype.afterComposeSuccess = function(result) { - LdapWizard.applyChanges(result); - if(this.countPending) { - this.countPending = false; - this.updateCount(); - } -}; - -LdapFilter.prototype.determineMode = function() { - var param = 'action=get'+encodeURIComponent(this.target)+'FilterMode'+ - '&ldap_serverconfig_chooser='+ - encodeURIComponent($('#ldap_serverconfig_chooser').val()); - - var filter = this; - LdapWizard.ajax(param, - function(result) { - var property = 'ldap' + filter.target + 'FilterMode'; - filter.mode = parseInt(result.changes[property], 10); - var rawContainerIsInvisible = - $('#raw'+filter.target+'FilterContainer').hasClass('invisible'); - if ( filter.mode === LdapWizard.filterModeRaw - && rawContainerIsInvisible - ) { - LdapWizard['toggleRaw'+filter.target+'Filter'](); - } else if ( filter.mode === LdapWizard.filterModeAssisted - && !rawContainerIsInvisible - ) { - LdapWizard['toggleRaw'+filter.target+'Filter'](); - } else { - console.log('LDAP Wizard determineMode: returned mode was »' + - filter.mode + '« of type ' + typeof filter.mode); - } - filter.unlock(); - filter.determineModeCallback(filter.mode); - }, - function () { - //on error case get back to default i.e. Assisted - if(!$('#raw'+filter.target+'FilterContainer').hasClass('invisible')) { - LdapWizard['toggleRaw'+filter.target+'Filter'](); - filter.mode = LdapWizard.filterModeAssisted; - } - filter.unlock(); - filter.determineModeCallback(filter.mode); - } - ); -}; - -LdapFilter.prototype.setMode = function(mode) { - if(mode === LdapWizard.filterModeAssisted || mode === LdapWizard.filterModeRaw) { - this.mode = mode; - } -}; - -LdapFilter.prototype.getMode = function() { - return this.mode; -}; - -LdapFilter.prototype.unlock = function() { - this.locked = false; - if(this.lazyRunCompose) { - this.lazyRunCompose = false; - this.compose(); - } -}; - -/** - * resets this.foundFeatures so that LDAP queries can be fired again to retrieve - * objectClasses, groups, etc. - */ -LdapFilter.prototype.reAllowFeatureLookup = function () { - this.foundFeatures = false; -}; - -LdapFilter.prototype.findFeatures = function() { - if(!this.foundFeatures && !this.locked && this.mode === LdapWizard.filterModeAssisted) { - this.foundFeatures = true; - var objcEl, avgrEl; - if(this.target === 'User') { - objcEl = 'ldap_userfilter_objectclass'; - avgrEl = 'ldap_userfilter_groups'; - } else if (this.target === 'Group') { - objcEl = 'ldap_groupfilter_objectclass'; - avgrEl = 'ldap_groupfilter_groups'; - } else if (this.target === 'Login') { - LdapWizard.findAttributes(); - return; - } else { - return false; - } - LdapWizard.findObjectClasses(objcEl, this.target); - LdapWizard.findAvailableGroups(avgrEl, this.target + "s"); - } -}; - -/** - * this function is triggered before user and group counts are executed - * resolving the passed status variable will fire up counting - */ -LdapFilter.prototype.beforeUpdateCount = function() { - var status = $.Deferred(); - LdapWizard.runDetectors(this.target, function() { - status.resolve(); - }); - return status; -}; - -LdapFilter.prototype.updateCount = function(doneCallback) { - var filter = this; - $.when(this.beforeUpdateCount()).done(function() { - if(filter.target === 'User') { - LdapWizard.countUsers(doneCallback); - } else if (filter.target === 'Group') { - LdapWizard.countGroups(doneCallback); - } - }); -}; diff --git a/apps/user_ldap/js/settings.js b/apps/user_ldap/js/settings.js deleted file mode 100644 index 768d62a18d1..00000000000 --- a/apps/user_ldap/js/settings.js +++ /dev/null @@ -1,1205 +0,0 @@ -var LdapConfiguration = { - refreshConfig: function() { - if($('#ldap_serverconfig_chooser option').length < 2) { - LdapConfiguration.addConfiguration(true); - return; - } - $.post( - OC.filePath('user_ldap','ajax','getConfiguration.php'), - $('#ldap_serverconfig_chooser').serialize(), - function (result) { - if(result.status === 'success') { - $.each(result.configuration, function(configkey, configvalue) { - elementID = '#'+configkey; - - //deal with Checkboxes - if($(elementID).is('input[type=checkbox]')) { - if(parseInt(configvalue, 10) === 1) { - $(elementID).attr('checked', 'checked'); - } else { - $(elementID).removeAttr('checked'); - } - return; - } - - //On Textareas, Multi-Line Settings come as array - if($(elementID).is('textarea') && $.isArray(configvalue)) { - configvalue = configvalue.join("\n"); - } - - // assign the value - $('#'+configkey).val(configvalue); - }); - LdapWizard.init(); - } - } - ); - }, - - resetDefaults: function() { - $('#ldap').find('input[type=text], input[type=number], input[type=password], textarea, select').each(function() { - if($(this).attr('id') === 'ldap_serverconfig_chooser') { - return; - } - $(this).val($(this).attr('data-default')); - }); - $('#ldap').find('input[type=checkbox]').each(function() { - if($(this).attr('data-default') === 1) { - $(this).attr('checked', 'checked'); - } else { - $(this).removeAttr('checked'); - } - }); - }, - - deleteConfiguration: function() { - $.post( - OC.filePath('user_ldap','ajax','deleteConfiguration.php'), - $('#ldap_serverconfig_chooser').serialize(), - function (result) { - if(result.status === 'success') { - $('#ldap_serverconfig_chooser option:selected').remove(); - $('#ldap_serverconfig_chooser option:first').select(); - LdapConfiguration.refreshConfig(); - } else { - OC.dialogs.alert( - result.message, - t('user_ldap', 'Deletion failed') - ); - } - } - ); - }, - - addConfiguration: function(doNotAsk) { - $.post( - OC.filePath('user_ldap','ajax','getNewServerConfigPrefix.php'), - function (result) { - if(result.status === 'success') { - if(doNotAsk) { - LdapConfiguration.resetDefaults(); - } else { - OC.dialogs.confirm( - t('user_ldap', 'Take over settings from recent server configuration?'), - t('user_ldap', 'Keep settings?'), - function(keep) { - if(!keep) { - LdapConfiguration.resetDefaults(); - } - } - ); - } - $('#ldap_serverconfig_chooser option:selected').removeAttr('selected'); - var html = '<option value="'+result.configPrefix+'" selected="selected">'+t('user_ldap','{nthServer}. Server', {nthServer: $('#ldap_serverconfig_chooser option').length})+'</option>'; - $('#ldap_serverconfig_chooser option:last').before(html); - LdapWizard.init(); - } else { - OC.dialogs.alert( - result.message, - t('user_ldap', 'Cannot add server configuration') - ); - } - } - ); - }, - - testConfiguration: function(onSuccess, onError) { - $.post( - OC.filePath('user_ldap','ajax','testConfiguration.php'), - $('#ldap').serialize(), - function (result) { - if (result.status === 'success') { - onSuccess(result); - } else { - onError(result); - } - } - ); - }, - - clearMappings: function(mappingSubject) { - $.post( - OC.filePath('user_ldap','ajax','clearMappings.php'), - 'ldap_clear_mapping='+encodeURIComponent(mappingSubject), - function(result) { - if(result.status === 'success') { - OC.dialogs.info( - t('user_ldap', 'mappings cleared'), - t('user_ldap', 'Success') - ); - } else { - OC.dialogs.alert( - result.message, - t('user_ldap', 'Error') - ); - } - } - ); - } -}; - -var LdapWizard = { - checkPortInfoShown: false, - saveBlacklist: {}, - userFilterGroupSelectState: 'enable', - spinner: '<img class="wizSpinner" src="'+ OC.imagePath('core', 'loading.gif') +'">', - filterModeAssisted: 0, - filterModeRaw: 1, - userFilter: false, - loginFilter: false, - groupFilter: false, - ajaxRequests: {}, - lastTestSuccessful: true, - - ajax: function(param, fnOnSuccess, fnOnError, reqID) { - if(!_.isUndefined(reqID)) { - if(LdapWizard.ajaxRequests.hasOwnProperty(reqID)) { - console.log('aborting ' + reqID); - console.log(param); - LdapWizard.ajaxRequests[reqID].abort(); - } - } - var request = $.post( - OC.filePath('user_ldap','ajax','wizard.php'), - param, - function(result) { - if(result.status === 'success') { - fnOnSuccess(result); - } else { - fnOnError(result); - } - } - ); - if(!_.isUndefined(reqID)) { - LdapWizard.ajaxRequests[reqID] = request; - } - return request; - }, - - applyChanges: function (result) { - for (var id in result.changes) { - LdapWizard.blacklistAdd(id); - if(id.indexOf('count') > 0) { - $('#'+id).text(result.changes[id]); - } else { - $('#'+id).val(result.changes[id]); - } - } - LdapWizard.functionalityCheck(); - - if($('#ldapSettings').tabs('option', 'active') == 0) { - LdapWizard.basicStatusCheck(); - } - }, - - enableTabs: function() { - //do not use this function directly, use basicStatusCheck instead. - if(LdapWizard.saveProcesses === 0) { - $('.ldap_action_continue').removeAttr('disabled'); - $('.ldap_action_back').removeAttr('disabled'); - $('#ldapSettings').tabs('option', 'disabled', []); - } - }, - - disableTabs: function() { - $('.ldap_action_continue').attr('disabled', 'disabled'); - $('.ldap_action_back').attr('disabled', 'disabled'); - $('#ldapSettings').tabs('option', 'disabled', [1, 2, 3, 4, 5]); - }, - - basicStatusCheck: function() { - //criteria to continue from the first tab - // - host, port, user filter, agent dn, password, base dn - var host = $('#ldap_host').val(); - var port = $('#ldap_port').val(); - var agent = $('#ldap_dn').val(); - var pwd = $('#ldap_agent_password').val(); - var base = $('#ldap_base').val(); - - if((host && port && base) && ((!agent && !pwd) || (agent && pwd))) { - LdapWizard.enableTabs(); - } else { - LdapWizard.disableTabs(); - } - }, - - - blacklistAdd: function(id) { - var obj = $('#' + id); - if(!(obj[0].hasOwnProperty('multiple') && obj[0]['multiple'] === true)) { - //no need to blacklist multiselect - LdapWizard.saveBlacklist[id] = true; - return true; - } - return false; - }, - - blacklistRemove: function(id) { - if(LdapWizard.saveBlacklist.hasOwnProperty(id)) { - delete LdapWizard.saveBlacklist[id]; - return true; - } - return false; - }, - - checkBaseDN: function() { - var host = $('#ldap_host').val(); - var port = $('#ldap_port').val(); - var user = $('#ldap_dn').val(); - var pass = $('#ldap_agent_password').val(); - - //FIXME: determine base dn with anonymous access - if(host && port && user && pass) { - var param = 'action=guessBaseDN'+ - '&ldap_serverconfig_chooser='+ - encodeURIComponent($('#ldap_serverconfig_chooser').val()); - - LdapWizard.showSpinner('#ldap_base'); - $('#ldap_base').prop('disabled', 'disabled'); - LdapWizard.ajax(param, - function(result) { - LdapWizard.applyChanges(result); - LdapWizard.hideSpinner('#ldap_base'); - if($('#ldap_base').val()) { - LdapWizard.hideInfoBox(); - } - $('#ldap_base').prop('disabled', false); - }, - function (result) { - LdapWizard.hideSpinner('#ldap_base'); - LdapWizard.showInfoBox(t('user_ldap', 'Please specify a Base DN')); - LdapWizard.showInfoBox(t('user_ldap', 'Could not determine Base DN')); - $('#ldap_base').prop('disabled', false); - }, - 'guessBaseDN' - ); - } - }, - - checkPort: function() { - var host = $('#ldap_host').val(); - var port = $('#ldap_port').val(); - - if(host && !port) { - var param = 'action=guessPortAndTLS'+ - '&ldap_serverconfig_chooser='+ - encodeURIComponent($('#ldap_serverconfig_chooser').val()); - - LdapWizard.showSpinner('#ldap_port'); - $('#ldap_port').prop('disabled', 'disabled'); - LdapWizard.ajax(param, - function(result) { - LdapWizard.applyChanges(result); - LdapWizard.hideSpinner('#ldap_port'); - if($('#ldap_port').val()) { - LdapWizard.checkBaseDN(); - $('#ldap_port').prop('disabled', false); - LdapWizard.hideInfoBox(); - } - }, - function (result) { - LdapWizard.hideSpinner('#ldap_port'); - $('#ldap_port').prop('disabled', false); - LdapWizard.showInfoBox(t('user_ldap', 'Please specify the port')); - }, - 'guessPortAndTLS' - ); - } - }, - - controlBack: function() { - var curTabIndex = $('#ldapSettings').tabs('option', 'active'); - if(curTabIndex == 0) { - return; - } - $('#ldapSettings').tabs('option', 'active', curTabIndex - 1); - LdapWizard.controlUpdate(curTabIndex - 1); - }, - - controlContinue: function() { - var curTabIndex = $('#ldapSettings').tabs('option', 'active'); - if(curTabIndex == 3) { - return; - } - $('#ldapSettings').tabs('option', 'active', 1 + curTabIndex); - LdapWizard.controlUpdate(curTabIndex + 1); - }, - - controlUpdate: function(nextTabIndex) { - if(nextTabIndex == 0) { - $('.ldap_action_back').addClass('invisible'); - $('.ldap_action_continue').removeClass('invisible'); - } else - if(nextTabIndex == 1) { - $('.ldap_action_back').removeClass('invisible'); - $('.ldap_action_continue').removeClass('invisible'); - } else - if(nextTabIndex == 2) { - $('.ldap_action_continue').removeClass('invisible'); - $('.ldap_action_back').removeClass('invisible'); - } else - if(nextTabIndex == 3) { - //now last tab - $('.ldap_action_back').removeClass('invisible'); - $('.ldap_action_continue').addClass('invisible'); - } - }, - - _countThings: function(method, spinnerID, doneCallback) { - var param = 'action='+method+ - '&ldap_serverconfig_chooser='+ - encodeURIComponent($('#ldap_serverconfig_chooser').val()); - - LdapWizard.showSpinner(spinnerID); - LdapWizard.ajax(param, - function(result) { - LdapWizard.applyChanges(result); - LdapWizard.hideSpinner(spinnerID); - if(!_.isUndefined(doneCallback)) { - doneCallback(method); - } - }, - function (result) { - OC.Notification.showTemporary('Counting the entries failed with: ' + result.message); - LdapWizard.hideSpinner(spinnerID); - if(!_.isUndefined(doneCallback)) { - doneCallback(method); - } - }, - method - ); - }, - - countGroups: function(doneCallback) { - var groupFilter = $('#ldap_group_filter').val(); - if(!_.isEmpty(groupFilter)) { - LdapWizard._countThings('countGroups', '#ldap_group_count', doneCallback); - } - }, - - countUsers: function(doneCallback) { - var userFilter = $('#ldap_userlist_filter').val(); - if(!_.isEmpty(userFilter)) { - LdapWizard._countThings('countUsers', '#ldap_user_count', doneCallback); - } - }, - - /** - * called after detectors have run - * @callback runDetectorsCallback - */ - - /** - * runs detectors to determine appropriate attributes, e.g. displayName - * @param {string} type either "User" or "Group" - * @param {runDetectorsCallback} triggered after all detectors have completed - */ - runDetectors: function(type, callback) { - if(type === 'Group') { - $.when(LdapWizard.detectGroupMemberAssoc()) - .then(callback, callback); - if( LdapWizard.admin.isExperienced - && !(LdapWizard.detectorsRunInXPMode & LdapWizard.groupDetectors)) { - LdapWizard.detectorsRunInXPMode += LdapWizard.groupDetectors; - } - } else if(type === 'User') { - var req1 = LdapWizard.detectUserDisplayNameAttribute(); - var req2 = LdapWizard.detectEmailAttribute(); - $.when(req1, req2) - .then(callback, callback); - if( LdapWizard.admin.isExperienced - && !(LdapWizard.detectorsRunInXPMode & LdapWizard.userDetectors)) { - LdapWizard.detectorsRunInXPMode += LdapWizard.userDetectors; - } - } - }, - - /** - * runs detector to find out a fitting user display name attribute - */ - detectUserDisplayNameAttribute: function() { - var param = 'action=detectUserDisplayNameAttribute' + - '&ldap_serverconfig_chooser='+ - encodeURIComponent($('#ldap_serverconfig_chooser').val()); - - //runs in the background, no callbacks necessary - return LdapWizard.ajax(param, LdapWizard.applyChanges, function(){}, 'detectUserDisplayNameAttribute'); - }, - - detectEmailAttribute: function() { - var param = 'action=detectEmailAttribute'+ - '&ldap_serverconfig_chooser='+ - encodeURIComponent($('#ldap_serverconfig_chooser').val()); - //runs in the background, no callbacks necessary - return LdapWizard.ajax(param, LdapWizard.applyChanges, function(){}, 'detectEmailAttribute'); - }, - - detectGroupMemberAssoc: function() { - param = 'action=determineGroupMemberAssoc'+ - '&ldap_serverconfig_chooser='+ - encodeURIComponent($('#ldap_serverconfig_chooser').val()); - - return LdapWizard.ajax(param, - function(result) { - //pure background story - }, - function (result) { - // error handling - }, - 'determineGroupMemberAssoc' - ); - }, - - findAttributes: function() { - param = 'action=determineAttributes'+ - '&ldap_serverconfig_chooser='+ - encodeURIComponent($('#ldap_serverconfig_chooser').val()); - - LdapWizard.showSpinner('#ldap_loginfilter_attributes'); - LdapWizard.ajax(param, - function(result) { - $('#ldap_loginfilter_attributes').find('option').remove(); - for (var i in result.options['ldap_loginfilter_attributes']) { - //FIXME: move HTML into template - var attr = result.options['ldap_loginfilter_attributes'][i]; - $('#ldap_loginfilter_attributes').append( - "<option value='"+attr+"'>"+attr+"</option>"); - } - LdapWizard.hideSpinner('#ldap_loginfilter_attributes'); - LdapWizard.applyChanges(result); - $('#ldap_loginfilter_attributes').multiselect('refresh'); - if($('#rawLoginFilterContainer').hasClass('invisible')) { - $('#ldap_loginfilter_attributes').multiselect('enable'); - } - LdapWizard.postInitLoginFilter(); - }, - function (result) { - //deactivate if no attributes found - $('#ldap_loginfilter_attributes').multiselect( - {noneSelectedText : 'No attributes found'}); - $('#ldap_loginfilter_attributes').multiselect('disable'); - LdapWizard.hideSpinner('#ldap_loginfilter_attributes'); - }, - 'determineAttributes' - ); - }, - - findAvailableGroups: function(multisel, type) { - if(type !== 'Users' && type !== 'Groups') { - return false; - } - param = 'action=determineGroupsFor'+encodeURIComponent(type)+ - '&ldap_serverconfig_chooser='+ - encodeURIComponent($('#ldap_serverconfig_chooser').val()); - - LdapWizard.showSpinner('#'+multisel); - LdapWizard.ajax(param, - function(result) { - $('#'+multisel).find('option').remove(); - for (var i in result.options[multisel]) { - //FIXME: move HTML into template - objc = result.options[multisel][i]; - $('#'+multisel).append("<option value='"+objc+"'>"+objc+"</option>"); - } - LdapWizard.hideSpinner('#'+multisel); - LdapWizard.applyChanges(result); - $('#'+multisel).multiselect('refresh'); - part = type.slice(0, -1); - if($('#raw' + part + 'FilterContainer').hasClass('invisible')) { - //enable only when raw filter editing is not turned on - $('#'+multisel).multiselect('enable'); - } - if(type === 'Users') { - //required for initial save - filter = $('#ldap_userlist_filter').val(); - if(!filter) { - LdapWizard.saveMultiSelect(multisel, - $('#'+multisel).multiselect("getChecked")); - } - LdapWizard.userFilterAvailableGroupsHasRun = true; - LdapWizard.postInitUserFilter(); - } - }, - function (result) { - LdapWizard.hideSpinner('#'+multisel); - $('#'+multisel).multiselect('disable'); - if(type === 'Users') { - LdapWizard.userFilterAvailableGroupsHasRun = true; - LdapWizard.postInitUserFilter(); - } - }, - 'findAvailableGroupsFor' + type - ); - }, - - findObjectClasses: function(multisel, type) { - if(type !== 'User' && type !== 'Group') { - return false; - } - var param = 'action=determine'+encodeURIComponent(type)+'ObjectClasses'+ - '&ldap_serverconfig_chooser='+ - encodeURIComponent($('#ldap_serverconfig_chooser').val()); - - LdapWizard.showSpinner('#'+multisel); - LdapWizard.ajax(param, - function(result) { - $('#'+multisel).find('option').remove(); - for (var i in result.options[multisel]) { - //FIXME: move HTML into template - objc = result.options[multisel][i]; - $('#'+multisel).append("<option value='"+objc+"'>"+objc+"</option>"); - } - LdapWizard.hideSpinner('#'+multisel); - LdapWizard.applyChanges(result); - $('#'+multisel).multiselect('refresh'); - if(type === 'User') { - //required for initial save - filter = $('#ldap_userlist_filter').val(); - if(!filter) { - LdapWizard.saveMultiSelect(multisel, - $('#'+multisel).multiselect("getChecked")); - } - LdapWizard.userFilterObjectClassesHasRun = true; - LdapWizard.postInitUserFilter(); - } - }, - function (result) { - LdapWizard.hideSpinner('#'+multisel); - if(type === 'User') { - LdapWizard.userFilterObjectClassesHasRun = true; - LdapWizard.postInitUserFilter(); - } - //TODO: error handling - }, - 'determine' + type + 'ObjectClasses' - ); - }, - - functionalityCheck: function() { - //criteria to enable the connection: - // - host, port, basedn, user filter, login filter - var host = $('#ldap_host').val(); - var port = $('#ldap_port').val(); - var base = $('#ldap_base').val(); - var userfilter = $('#ldap_userlist_filter').val(); - var loginfilter = $('#ldap_login_filter').val(); - - //FIXME: activates a manually deactivated configuration. - if(host && port && base && userfilter && loginfilter) { - LdapWizard.updateStatusIndicator(true); - if($('#ldap_configuration_active').is(':checked')) { - return; - } - if(!LdapWizard.isConfigurationActiveControlLocked) { - //avoids a manually deactivated connection will be activated - //upon opening the admin page - $('#ldap_configuration_active').prop('checked', true); - LdapWizard.save($('#ldap_configuration_active')[0]); - } - } else { - if($('#ldap_configuration_active').is(':checked')) { - $('#ldap_configuration_active').prop('checked', false); - LdapWizard.save($('#ldap_configuration_active')[0]); - } - LdapWizard.updateStatusIndicator(false); - } - }, - - hideInfoBox: function() { - if(LdapWizard.checkInfoShown) { - $('#ldapWizard1 .ldapWizardInfo').addClass('invisible'); - LdapWizard.checkInfoShown = false; - } - }, - - hideSpinner: function(id) { - $(id+' + .wizSpinner').remove(); - $(id + " + button").css('display', 'inline'); - }, - - isConfigurationActiveControlLocked: true, - detectorsRunInXPMode: 0, - userDetectors: 1, - groupDetectors: 2, - - init: function() { - LdapWizard.detectorsRunInXPMode = 0; - LdapWizard.instantiateFilters(); - LdapWizard.admin.setExperienced($('#ldap_experienced_admin').is(':checked')); - LdapWizard.lastTestSuccessful = true; - LdapWizard.basicStatusCheck(); - LdapWizard.functionalityCheck(); - LdapWizard.isConfigurationActiveControlLocked = false; - }, - - initGroupFilter: function() { - LdapWizard.groupFilter.activate(); - }, - - /** init login filter tab section **/ - - initLoginFilter: function() { - LdapWizard.loginFilter.activate(); - }, - - postInitLoginFilter: function() { - if($('#rawLoginFilterContainer').hasClass('invisible')) { - LdapWizard.loginFilter.compose(); - } - }, - - /** end of init user filter tab section **/ - - initMultiSelect: function(object, id, caption) { - object.multiselect({ - header: false, - selectedList: 9, - noneSelectedText: caption, - click: function(event, ui) { - LdapWizard.saveMultiSelect(id, - $('#'+id).multiselect("getChecked")); - } - }); - }, - - hideTestSpinner:function (countMethod) { - var selector; - if(countMethod === 'countUsers') { - selector = '#rawUserFilterContainer .ldapGetEntryCount'; - } else { - selector = '#rawGroupFilterContainer .ldapGetEntryCount'; - } - LdapWizard.hideSpinner(selector); - }, - - /** init user filter tab section **/ - - instantiateFilters: function() { - delete LdapWizard.userFilter; - LdapWizard.userFilter = new LdapFilter('User', function(mode) { - if( !LdapWizard.admin.isExperienced() - || mode === LdapWizard.filterModeAssisted) { - LdapWizard.userFilter.updateCount(); - } - LdapWizard.userFilter.findFeatures(); - }); - $('#rawUserFilterContainer .ldapGetEntryCount').click(function(event) { - event.preventDefault(); - $('#ldap_user_count').text(''); - LdapWizard.showSpinner('#rawUserFilterContainer .ldapGetEntryCount'); - LdapWizard.userFilter.updateCount(LdapWizard.hideTestSpinner); - $('#ldap_user_count').removeClass('hidden'); - }); - - delete LdapWizard.loginFilter; - LdapWizard.loginFilter = new LdapFilter('Login', function(mode) { - LdapWizard.loginFilter.findFeatures(); - }); - - delete LdapWizard.groupFilter; - LdapWizard.groupFilter = new LdapFilter('Group', function(mode) { - if( !LdapWizard.admin.isExperienced() - || mode === LdapWizard.filterModeAssisted) { - LdapWizard.groupFilter.updateCount(); - } - LdapWizard.groupFilter.findFeatures(); - }); - $('#rawGroupFilterContainer .ldapGetEntryCount').click(function(event) { - event.preventDefault(); - $('#ldap_group_count').text(''); - LdapWizard.showSpinner('#rawGroupFilterContainer .ldapGetEntryCount'); - LdapWizard.groupFilter.updateCount(LdapWizard.hideTestSpinner); - $('#ldap_group_count').removeClass('hidden'); - }); - }, - - userFilterObjectClassesHasRun: false, - userFilterAvailableGroupsHasRun: false, - - initUserFilter: function() { - LdapWizard.userFilterObjectClassesHasRun = false; - LdapWizard.userFilterAvailableGroupsHasRun = false; - LdapWizard.userFilter.activate(); - }, - - postInitUserFilter: function() { - if(LdapWizard.userFilterObjectClassesHasRun && - LdapWizard.userFilterAvailableGroupsHasRun) { - LdapWizard.userFilter.compose(); - } - }, - - /** end of init user filter tab section **/ - - onTabChange: function(event, ui) { - if(LdapWizard.saveProcesses > 0) { - //do not allow to switch tabs as long as a save process is active - return false; - } - var newTabIndex = 0; - if(ui.newTab[0].id === '#ldapWizard2') { - LdapWizard.initUserFilter(); - newTabIndex = 1; - } else if(ui.newTab[0].id === '#ldapWizard3') { - LdapWizard.initLoginFilter(); - newTabIndex = 2; - } else if(ui.newTab[0].id === '#ldapWizard4') { - LdapWizard.initGroupFilter(); - newTabIndex = 3; - } - - var curTabIndex = $('#ldapSettings').tabs('option', 'active'); - if(curTabIndex >= 0 && curTabIndex <= 3) { - LdapWizard.controlUpdate(newTabIndex); - //run detectors in XP mode, when "Test Filter" button has not been - //clicked in order to make sure that email, displayname, member- - //group association attributes are properly set. - if( curTabIndex === 1 - && LdapWizard.admin.isExperienced - && !(LdapWizard.detecorsRunInXPMode & LdapWizard.userDetectors) - ) { - LdapWizard.runDetectors('User', function(){}); - } else if( curTabIndex === 3 - && LdapWizard.admin.isExperienced - && !(LdapWizard.detecorsRunInXPMode & LdapWizard.groupDetectors) - ) { - LdapWizard.runDetectors('Group', function(){}); - } - } - }, - - /** - * allows UserFilter, LoginFilter and GroupFilter to lookup objectClasses - * and similar again. This should be called after essential changes, e.g. - * Host or BaseDN changes, or positive functionality check - * - */ - allowFilterFeatureSearch: function () { - LdapWizard.userFilter.reAllowFeatureLookup(); - LdapWizard.loginFilter.reAllowFeatureLookup(); - LdapWizard.groupFilter.reAllowFeatureLookup(); - }, - - processChanges: function (triggerObj) { - LdapWizard.hideInfoBox(); - - if(triggerObj.id === 'ldap_host' - || triggerObj.id === 'ldap_port' - || triggerObj.id === 'ldap_dn' - || triggerObj.id === 'ldap_agent_password') { - LdapWizard.checkPort(); - if($('#ldap_port').val()) { - //if Port is already set, check BaseDN - LdapWizard.checkBaseDN(); - LdapWizard.allowFilterFeatureSearch(); - } - } - - if(triggerObj.id === 'ldap_loginfilter_username' - || triggerObj.id === 'ldap_loginfilter_email') { - LdapWizard.loginFilter.compose(); - } else if (!LdapWizard.admin.isExperienced()) { - if(triggerObj.id === 'ldap_userlist_filter') { - LdapWizard.userFilter.updateCount(); - } else if (triggerObj.id === 'ldap_group_filter') { - LdapWizard.groupFilter.updateCount(); - } - } - - if($('#ldapSettings').tabs('option', 'active') == 0) { - LdapWizard.basicStatusCheck(); - LdapWizard.functionalityCheck(); - } - }, - - save: function(inputObj) { - if(LdapWizard.blacklistRemove(inputObj.id)) { - return; - } - if($(inputObj).is('input[type=checkbox]') - && !$(inputObj).is(':checked')) { - val = 0; - } else { - val = $(inputObj).val(); - } - LdapWizard._save(inputObj, val); - }, - - /** - * updates user or group count on multiSelect close. Resets the event - * function subsequently. - * - * @param {LdapFilter} filter - * @param {Object} $multiSelectObj - */ - onMultiSelectClose: function(filter, $multiSelectObj) { - filter.updateCount(); - $multiSelectObj.multiselect({close: function(){}}); - }, - - saveMultiSelect: function(originalObj, resultObj) { - var values = ''; - for(var i = 0; i < resultObj.length; i++) { - values = values + "\n" + resultObj[i].value; - } - LdapWizard._save($('#'+originalObj)[0], $.trim(values)); - var $multiSelectObj = $('#'+originalObj); - var updateCount = !$multiSelectObj.multiselect("isOpen"); - var applyUpdateOnCloseToFilter; - if(originalObj === 'ldap_userfilter_objectclass' - || originalObj === 'ldap_userfilter_groups') { - LdapWizard.userFilter.compose(updateCount); - if(!updateCount) { - applyUpdateOnCloseToFilter = LdapWizard.userFilter; - } - //when user filter is changed afterwards, login filter needs to - //be adjusted, too - if(!LdapWizard.loginFilter) { - LdapWizard.initLoginFilter(); - } - LdapWizard.loginFilter.compose(); - } else if(originalObj === 'ldap_loginfilter_attributes') { - LdapWizard.loginFilter.compose(); - } else if(originalObj === 'ldap_groupfilter_objectclass' - || originalObj === 'ldap_groupfilter_groups') { - LdapWizard.groupFilter.compose(updateCount); - if(!updateCount) { - applyUpdateOnCloseToFilter = LdapWizard.groupFilter; - } - } - - if(applyUpdateOnCloseToFilter instanceof LdapFilter) { - $multiSelectObj.multiselect({ - close: function () { - LdapWizard.onMultiSelectClose( - applyUpdateOnCloseToFilter, $multiSelectObj); - } - }); - } - }, - - saveProcesses: 0, - _save: function(object, value) { - $('#ldap .ldap_saving').removeClass('hidden'); - LdapWizard.saveProcesses += 1; - $('#ldap *').addClass('save-cursor'); - param = 'cfgkey='+encodeURIComponent(object.id)+ - '&cfgval='+encodeURIComponent(value)+ - '&action=save'+ - '&ldap_serverconfig_chooser='+$('#ldap_serverconfig_chooser').val(); - - $.post( - OC.filePath('user_ldap','ajax','wizard.php'), - param, - function(result) { - LdapWizard.saveProcesses -= 1; - if(LdapWizard.saveProcesses === 0) { - $('#ldap .ldap_saving').addClass('hidden'); - $('#ldap *').removeClass('save-cursor'); - } - if(result.status === 'success') { - LdapWizard.processChanges(object); - } else { - console.log('Could not save value for ' + object.id); - } - } - ); - }, - - showInfoBox: function(text) { - $('#ldapWizard1 .ldapWizardInfo').text(text); - $('#ldapWizard1 .ldapWizardInfo').removeClass('invisible'); - LdapWizard.checkInfoShown = true; - }, - - showSpinner: function(id) { - if($(id + ' + .wizSpinner').length == 0) { - $(LdapWizard.spinner).insertAfter($(id)); - $(id + " + img + button").css('display', 'none'); - } - }, - - toggleRawFilter: function(container, moc, mg, stateVar, modeKey) { - var isUser = moc.indexOf('user') >= 0; - var filter = isUser ? LdapWizard.userFilter : LdapWizard.groupFilter; - //moc = multiselect objectclass - //mg = mutliselect groups - if($(container).hasClass('invisible')) { - filter.setMode(LdapWizard.filterModeRaw); - $(container).removeClass('invisible'); - $(moc).multiselect('disable'); - if($(mg).multiselect().attr('disabled') === 'disabled') { - LdapWizard[stateVar] = 'disable'; - } else { - LdapWizard[stateVar] = 'enable'; - } - $(mg).multiselect('disable'); - LdapWizard._save({ id: modeKey }, LdapWizard.filterModeRaw); - } else { - filter.setMode(LdapWizard.filterModeAssisted); - filter.findFeatures(); - $(container).addClass('invisible'); - $(mg).multiselect(LdapWizard[stateVar]); - $(moc).multiselect('enable'); - LdapWizard._save({ id: modeKey }, LdapWizard.filterModeAssisted); - if(isUser) { - LdapWizard.blacklistRemove('ldap_userlist_filter'); - LdapWizard.userFilter.compose(true); - } else { - LdapWizard.blacklistRemove('ldap_group_filter'); - LdapWizard.groupFilter.compose(true); - } - } - }, - - onToggleRawFilterConfirmation: function(currentMode, isRawVisible, callback) { - if( !LdapWizard.admin.isExperienced() - || currentMode === LdapWizard.filterModeAssisted - || (LdapWizard.admin.isExperienced() && !isRawVisible) - ) { - return callback(true); - } - - var confirmed = OCdialogs.confirm( - 'Switching the mode will enable automatic LDAP queries. Depending on your LDAP size they may take a while. Do you still want to switch the mode?', - 'Mode switch', - callback - ); - }, - - toggleRawGroupFilter: function() { - LdapWizard.onToggleRawFilterConfirmation( - LdapWizard.groupFilter.getMode(), - !$('#rawGroupFilterContainer').hasClass('invisible'), - function(confirmed) { - if(confirmed !== true) { - return; - } - - LdapWizard.blacklistRemove('ldap_group_filter'); - LdapWizard.toggleRawFilter('#rawGroupFilterContainer', - '#ldap_groupfilter_objectclass', - '#ldap_groupfilter_groups', - 'groupFilterGroupSelectState', - 'ldapGroupFilterMode' - ); - LdapWizard.admin.updateGroupTab(LdapWizard.groupFilter.getMode()); - } - ); - }, - - toggleRawLoginFilter: function() { - LdapWizard.onToggleRawFilterConfirmation( - LdapWizard.loginFilter.getMode(), - !$('#rawLoginFilterContainer').hasClass('invisible'), - function(confirmed) { - if(confirmed !== true) { - return; - } - - LdapWizard.blacklistRemove('ldap_login_filter'); - container = '#rawLoginFilterContainer'; - if($(container).hasClass('invisible')) { - $(container).removeClass('invisible'); - action = 'disable'; - property = 'disabled'; - mode = LdapWizard.filterModeRaw; - } else { - $(container).addClass('invisible'); - action = 'enable'; - property = false; - mode = LdapWizard.filterModeAssisted; - } - LdapWizard.loginFilter.setMode(mode); - LdapWizard.loginFilter.findFeatures(); - $('#ldap_loginfilter_attributes').multiselect(action); - $('#ldap_loginfilter_email').prop('disabled', property); - $('#ldap_loginfilter_username').prop('disabled', property); - LdapWizard._save({ id: 'ldapLoginFilterMode' }, mode); - if(action === 'enable') { - LdapWizard.loginFilter.compose(); - } - } - ); - }, - - toggleRawUserFilter: function() { - LdapWizard.onToggleRawFilterConfirmation( - LdapWizard.userFilter.getMode(), - !$('#rawUserFilterContainer').hasClass('invisible'), - function(confirmed) { - if(confirmed === true) { - LdapWizard.blacklistRemove('ldap_userlist_filter'); - LdapWizard.toggleRawFilter('#rawUserFilterContainer', - '#ldap_userfilter_objectclass', - '#ldap_userfilter_groups', - 'userFilterGroupSelectState', - 'ldapUserFilterMode' - ); - LdapWizard.admin.updateUserTab(LdapWizard.userFilter.getMode()); - } - } - ); - }, - - updateStatusIndicator: function(isComplete) { - if(isComplete) { - LdapConfiguration.testConfiguration( - //onSuccess - function(result) { - $('.ldap_config_state_indicator').text(t('user_ldap', - 'Configuration OK' - )); - $('.ldap_config_state_indicator').addClass('ldap_grey'); - $('.ldap_config_state_indicator_sign').removeClass('error'); - $('.ldap_config_state_indicator_sign').addClass('success'); - if(!LdapWizard.lastTestSuccessful) { - LdapWizard.lastTestSuccessful = true; - LdapWizard.allowFilterFeatureSearch(); - } - }, - //onError - function(result) { - $('.ldap_config_state_indicator').text(t('user_ldap', - 'Configuration incorrect' - )); - $('.ldap_config_state_indicator').removeClass('ldap_grey'); - $('.ldap_config_state_indicator_sign').addClass('error'); - $('.ldap_config_state_indicator_sign').removeClass('success'); - LdapWizard.lastTestSuccessful = false; - } - ); - } else { - $('.ldap_config_state_indicator').text(t('user_ldap', - 'Configuration incomplete' - )); - $('.ldap_config_state_indicator').removeClass('ldap_grey'); - $('.ldap_config_state_indicator_sign').removeClass('error'); - $('.ldap_config_state_indicator_sign').removeClass('success'); - } - } -}; - -$(document).ready(function() { - $('#ldapAdvancedAccordion').accordion({ heightStyle: 'content', animate: 'easeInOutCirc'}); - $('#ldapSettings').tabs({ beforeActivate: LdapWizard.onTabChange }); - $('.ldap_submit').button(); - $('.ldap_action_test_connection').button(); - $('#ldap_action_delete_configuration').button(); - LdapWizard.initMultiSelect($('#ldap_userfilter_groups'), - 'ldap_userfilter_groups', - t('user_ldap', 'Select groups')); - LdapWizard.initMultiSelect($('#ldap_userfilter_objectclass'), - 'ldap_userfilter_objectclass', - t('user_ldap', 'Select object classes')); - LdapWizard.initMultiSelect($('#ldap_loginfilter_attributes'), - 'ldap_loginfilter_attributes', - t('user_ldap', 'Select attributes')); - LdapWizard.initMultiSelect($('#ldap_groupfilter_groups'), - 'ldap_groupfilter_groups', - t('user_ldap', 'Select groups')); - LdapWizard.initMultiSelect($('#ldap_groupfilter_objectclass'), - 'ldap_groupfilter_objectclass', - t('user_ldap', 'Select object classes')); - - $('.lwautosave').change(function() { LdapWizard.save(this); }); - $('#toggleRawUserFilter').click(LdapWizard.toggleRawUserFilter); - $('#toggleRawGroupFilter').click(LdapWizard.toggleRawGroupFilter); - $('#toggleRawLoginFilter').click(LdapWizard.toggleRawLoginFilter); - LdapConfiguration.refreshConfig(); - $('.ldap_action_continue').click(function(event) { - event.preventDefault(); - LdapWizard.controlContinue(); - }); - $('.ldap_action_back').click(function(event) { - event.preventDefault(); - LdapWizard.controlBack(); - }); - $('.ldap_action_test_connection').click(function(event){ - event.preventDefault(); - LdapConfiguration.testConfiguration( - //onSuccess - function(result) { - OC.dialogs.alert( - result.message, - t('user_ldap', 'Connection test succeeded') - ); - }, - //onError - function(result) { - OC.dialogs.alert( - result.message, - t('user_ldap', 'Connection test failed') - ); - } - ); - }); - - $('#ldap_action_delete_configuration').click(function(event) { - event.preventDefault(); - OC.dialogs.confirm( - t('user_ldap', 'Do you really want to delete the current Server Configuration?'), - t('user_ldap', 'Confirm Deletion'), - function(deleteConfiguration) { - if(deleteConfiguration) { - LdapConfiguration.deleteConfiguration(); - } - } - ); - }); - - $('.ldap_submit').click(function(event) { - event.preventDefault(); - $.post( - OC.filePath('user_ldap','ajax','setConfiguration.php'), - $('#ldap').serialize(), - function (result) { - bgcolor = $('.ldap_submit').css('background'); - if (result.status === 'success') { - //the dealing with colors is a but ugly, but the jQuery version in use has issues with rgba colors - $('.ldap_submit').css('background', '#fff'); - $('.ldap_submit').effect('highlight', {'color':'#A8FA87'}, 5000, function() { - $('.ldap_submit').css('background', bgcolor); - }); - //update the Label in the config chooser - caption = $('#ldap_serverconfig_chooser option:selected:first').text(); - pretext = '. Server: '; - caption = caption.slice(0, caption.indexOf(pretext) + pretext.length); - caption = caption + $('#ldap_host').val(); - $('#ldap_serverconfig_chooser option:selected:first').text(caption); - - } else { - $('.ldap_submit').css('background', '#fff'); - $('.ldap_submit').effect('highlight', {'color':'#E97'}, 5000, function() { - $('.ldap_submit').css('background', bgcolor); - }); - } - } - ); - }); - - $('#ldap_action_clear_user_mappings').click(function(event) { - event.preventDefault(); - LdapConfiguration.clearMappings('user'); - }); - - $('#ldap_action_clear_group_mappings').click(function(event) { - event.preventDefault(); - LdapConfiguration.clearMappings('group'); - }); - - $('#ldap_serverconfig_chooser').change(function(event) { - value = $('#ldap_serverconfig_chooser option:selected:first').attr('value'); - if(value === 'NEW') { - LdapConfiguration.addConfiguration(false); - } else { - LdapConfiguration.refreshConfig(); - } - }); - - expAdminCB = $('#ldap_experienced_admin'); - LdapWizard.admin = new ExperiencedAdmin(LdapWizard, expAdminCB.is(':checked')); - expAdminCB.change(function() { - LdapWizard.admin.setExperienced($(this).is(':checked')); - }); -}); diff --git a/apps/user_ldap/js/wizard/configModel.js b/apps/user_ldap/js/wizard/configModel.js new file mode 100644 index 00000000000..c3f1e85b592 --- /dev/null +++ b/apps/user_ldap/js/wizard/configModel.js @@ -0,0 +1,606 @@ +/** + * Copyright (c) 2015, Arthur Schiwon <blizzz@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or later. + * See the COPYING-README file. + */ + +OCA = OCA || {}; + +(function() { + + /** + * @classdesc this class represents a server configuration. It communicates + * with the ownCloud server to ensure to always have the up to date LDAP + * configuration. It sends various events that views can listen to and + * provides methods so they can modify the configuration based upon user + * input. This model is also extended by so-called "detectors" who let the + * ownCloud server try to auto-detect settings and manipulate the + * configuration as well. + * + * @constructor + */ + var ConfigModel = function() {}; + + ConfigModel.prototype = { + /** @constant {number} */ + FILTER_MODE_ASSISTED: 0, + /** @constant {number} */ + FILTER_MODE_RAW: 1, + + /** + * initializes the instance. Always call it after creating the instance. + * + * @param {OCA.LDAP.Wizard.WizardDetectorQueue} detectorQueue + */ + init: function (detectorQueue) { + /** @type {object} holds the configuration in key-value-pairs */ + this.configuration = {}; + /** @type {object} holds the subscribers that listen to the events */ + this.subscribers = {}; + /** @type {Array} holds registered detectors */ + this.detectors = []; + /** @type {boolean} whether a configuration is currently loading */ + this.loadingConfig = false; + + if(detectorQueue instanceof OCA.LDAP.Wizard.WizardDetectorQueue) { + /** @type {OCA.LDAP.Wizard.WizardDetectorQueue} */ + this.detectorQueue = detectorQueue; + } + }, + + /** + * loads a specified configuration + * + * @param {string} [configID] - the configuration id (or prefix) + */ + load: function (configID) { + if(this.loadingConfig) { + return; + } + this._resetDetectorQueue(); + + this.configID = configID; + var url = OC.generateUrl('apps/user_ldap/ajax/getConfiguration.php'); + var params = OC.buildQueryString({ldap_serverconfig_chooser: configID}); + this.loadingConfig = true; + var model = this; + $.post(url, params, function (result) { model._processLoadConfig(model, result) }); + }, + + /** + * creates a new LDAP configuration + * + * @param {boolean} [copyCurrent] - if true, the current configuration + * is copied, otherwise a blank one is created. + */ + newConfig: function(copyCurrent) { + this._resetDetectorQueue(); + + var url = OC.generateUrl('apps/user_ldap/ajax/getNewServerConfigPrefix.php'); + var params = {}; + if(copyCurrent === true) { + params['copyConfig'] = this.configID; + } + params = OC.buildQueryString(params); + var model = this; + copyCurrent = _.isUndefined(copyCurrent) ? false : copyCurrent; + $.post(url, params, function (result) { model._processNewConfigPrefix(model, result, copyCurrent) }); + }, + + /** + * deletes the current configuration. This method will not ask for + * confirmation, if desired it needs to be ensured by the caller. + * + * @param {string} [configID] - the configuration id (or prefix) + */ + deleteConfig: function(configID) { + var url = OC.generateUrl('apps/user_ldap/ajax/deleteConfiguration.php'); + var params = OC.buildQueryString({ldap_serverconfig_chooser: configID}); + var model = this; + $.post(url, params, function (result) { model._processDeleteConfig(model, result, configID) }); + }, + + /** + * @callback wizardCallBack + * @param {ConfigModel} [model] + * @param {OCA.LDAP.Wizard.WizardDetectorGeneric} [detector] + * @param {object} [result] - response from the ajax request + */ + + /** + * calls an AJAX endpoint at ownCloud. This method should be called by + * detectors only! + * + * @param {string} [params] - as return by OC.buildQueryString + * @param {wizardCallBack} [callback] + * @param {OCA.LDAP.Wizard.WizardDetectorGeneric} [detector] + * @returns {jqXHR} + */ + callWizard: function(params, callback, detector) { + return this.callAjax('wizard.php', params, callback, detector); + }, + + /** + * calls an AJAX endpoint at ownCloud. This method should be called by + * detectors only! + * + * @param {string} destination - the desired end point + * @param {string} [params] - as return by OC.buildQueryString + * @param {wizardCallBack} [callback] + * @param {OCA.LDAP.Wizard.WizardDetectorGeneric} [detector] + * @returns {jqXHR} + */ + callAjax: function(destination, params, callback, detector) { + var url = OC.generateUrl('apps/user_ldap/ajax/' + destination); + var model = this; + return $.post(url, params, function (result) { + callback(model, detector,result); + }); + }, + + /** + * setRequested Event + * + * @event ConfigModel#setRequested + * @type{object} - empty + */ + + /** + * modifies a configuration key. If a provided configuration key does + * not exist or the provided value equals the current setting, false is + * returned. Otherwise ownCloud server will be called to save the new + * value, an event will notify when this is done. True is returned when + * the request is sent, however it does not mean whether saving was + * successful or not. + * + * This method is supposed to be called by views, after the user did a + * change which needs to be saved. + * + * @param {string} [key] + * @param {string|number} [value] + * @returns {boolean} + * @fires {ConfigModel#setRequested} + */ + set: function(key, value) { + if(_.isUndefined(this.configuration[key])) { + console.warn('will not save undefined key: ' + key); + return false; + } + if(this.configuration[key] === value) { + return false; + } + this._broadcast('setRequested', {}); + var url = OC.generateUrl('apps/user_ldap/ajax/wizard.php'); + var objParams = { + ldap_serverconfig_chooser: this.configID, + action: 'save', + cfgkey: key, + cfgval: value + }; + var strParams = OC.buildQueryString(objParams); + var model = this; + $.post(url, strParams, function(result) { model._processSetResult(model, result, objParams) }); + return true; + }, + + /** + * configUpdated Event + * + * object property is a key-value-pair of the configuration key as index + * and its value. + * + * @event ConfigModel#configUpdated + * @type{object} + */ + + /** + * updates the model's configuration data. This should be called only, + * when a new configuration value was received from the ownCloud server. + * This is typically done by detectors, but never by views. + * + * Cancels with false if old and new values already match. + * + * @param {string} [key] + * @param {string} [value] + * @returns {boolean} + * @fires ConfigModel#configUpdated + */ + update: function(key, value) { + if(this.configuration[key] === value) { + return false; + } + if(!_.isUndefined(this.configuration[key])) { + // don't write e.g. count values to the configuration + // they don't go as feature, yet + this.configuration[key] = value; + } + var configPart = {}; + configPart[key] = value; + this._broadcast('configUpdated', configPart); + }, + + /** + * @typedef {object} FeaturePayload + * @property {string} feature + * @property {Array} data + */ + + /** + * informs about a detected LDAP "feature" (wider sense). For examples, + * the detected object classes for users or groups + * + * @param {FeaturePayload} payload + */ + inform: function(payload) { + this._broadcast('receivedLdapFeature', payload); + }, + + /** + * @typedef {object} ErrorPayload + * @property {string} message + * @property {string} relatedKey + */ + + /** + * broadcasts an error message, if a wizard reply ended up in an error. + * To be called by detectors. + * + * @param {ErrorPayload} payload + */ + gotServerError: function(payload) { + this._broadcast('serverError', payload); + }, + + /** + * detectionStarted Event + * + * @event ConfigModel#detectionStarted + * @type{string} - the target configuration key that is being + * auto-detected + */ + + /** + * lets the model broadcast the info that a detector starts to run + * + * supposed to be called by detectors only + * + * @param {string} [key] + * @fires ConfigModel#detectionStarted + */ + notifyAboutDetectionStart: function(key) { + this._broadcast('detectionStarted', key); + }, + + /** + * detectionCompleted Event + * + * @event ConfigModel#detectionCompleted + * @type{string} - the target configuration key that was + * auto-detected + */ + + /** + * lets the model broadcast the info that a detector run was completed + * + * supposed to be called by detectors only + * + * @param {string} [key] + * @fires ConfigModel#detectionCompleted + */ + notifyAboutDetectionCompletion: function(key) { + this._broadcast('detectionCompleted', key); + }, + + /** + * @callback listenerCallback + * @param {OCA.LDAP.Wizard.WizardTabGeneric|OCA.LDAP.Wizard.WizardView} [view] + * @param {object} [params] + */ + + /** + * registers a listener to an event + * + * the idea is that only views listen. + * + * @param {string} [name] - the event name + * @param {listenerCallback} [fn] + * @param {OCA.LDAP.Wizard.WizardTabGeneric|OCA.LDAP.Wizard.WizardView} [context] + */ + on: function(name, fn, context) { + if(_.isUndefined(this.subscribers[name])) { + this.subscribers[name] = []; + } + this.subscribers[name].push({fn: fn, context: context}); + }, + + /** + * starts a configuration test on the ownCloud server + */ + requestConfigurationTest: function() { + var url = OC.generateUrl('apps/user_ldap/ajax/testConfiguration.php'); + var params = OC.buildQueryString(this.configuration); + var model = this; + $.post(url, params, function(result) { model._processTestResult(model, result) }); + //TODO: make sure only one test is running at a time + }, + + /** + * the view may request a call to the wizard, for instance to fetch + * object classes or groups + * + * @param {string} featureKey + * @param {Object} [additionalParams] + */ + requestWizard: function(featureKey, additionalParams) { + var model = this; + var detectorCount = this.detectors.length; + var found = false; + for(var i = 0; i < detectorCount; i++) { + if(this.detectors[i].runsOnFeatureRequest(featureKey)) { + found = true; + (function (detector) { + model.detectorQueue.add(function() { + return detector.run(model, model.configID, additionalParams); + }); + })(model.detectors[i]); + } + } + if(!found) { + console.warn('No detector found for feature ' + featureKey); + } + }, + + /** + * resets the detector queue + * + * @private + */ + _resetDetectorQueue: function() { + if(!_.isUndefined(this.detectorQueue)) { + this.detectorQueue.reset(); + } + }, + + /** + * detectors can be registered herewith + * + * @param {OCA.LDAP.Wizard.WizardDetectorGeneric} [detector] + */ + registerDetector: function(detector) { + if(detector instanceof OCA.LDAP.Wizard.WizardDetectorGeneric) { + this.detectors.push(detector); + } + }, + + /** + * emits an event + * + * @param {string} [name] - the event name + * @param {*} [params] + * @private + */ + _broadcast: function(name, params) { + if(_.isUndefined(this.subscribers[name])) { + return; + } + var subscribers = this.subscribers[name]; + var subscriberCount = subscribers.length; + for(var i = 0; i < subscriberCount; i++) { + if(_.isUndefined(subscribers[i]['fn'])) { + console.warn('callback method is not defined. Event ' + name); + continue; + } + subscribers[i]['fn'](subscribers[i]['context'], params); + } + }, + + /** + * ConfigModel#configLoaded Event + * + * @event ConfigModel#configLoaded + * @type {object} - LDAP configuration as key-value-pairs + */ + + /** + * @typedef {object} ConfigLoadResponse + * @property {string} [status] + * @property {object} [configuration] - only present if status equals 'success' + */ + + /** + * processes the ajax response of a configuration load request + * + * @param {ConfigModel} [model] + * @param {ConfigLoadResponse} [result] + * @fires ConfigModel#configLoaded + * @private + */ + _processLoadConfig: function(model, result) { + model.configuration = {}; + if(result['status'] === 'success') { + $.each(result['configuration'], function(key, value) { + model.configuration[key] = value; + }); + } + model.loadingConfig = false; + model._broadcast('configLoaded', model.configuration); + }, + + /** + * @typedef {object} ConfigSetPayload + * @property {boolean} [isSuccess] + * @property {string} [key] + * @property {string} [value] + * @property {string} [errorMessage] + */ + + /** + * ConfigModel#setCompleted Event + * + * @event ConfigModel#setCompleted + * @type {ConfigSetPayload} + */ + + /** + * @typedef {object} ConfigSetResponse + * @property {string} [status] + * @property {object} [message] - might be present only in error cases + */ + + /** + * processes the ajax response of a configuration key set request + * + * @param {ConfigModel} [model] + * @param {ConfigSetResponse} [result] + * @param {object} [params] - the original changeSet + * @fires ConfigModel#configLoaded + * @private + */ + _processSetResult: function(model, result, params) { + var isSuccess = (result['status'] === 'success'); + if(isSuccess) { + model.configuration[params.cfgkey] = params.cfgval; + } + var payload = { + isSuccess: isSuccess, + key: params.cfgkey, + value: model.configuration[params.cfgkey], + errorMessage: _.isUndefined(result['message']) ? '' : result['message'] + }; + model._broadcast('setCompleted', payload); + + // let detectors run + // NOTE: detector's changes will not result in new _processSetResult + // calls, … in case they interfere it is because of this ;) + if(_.isUndefined(model.detectorQueue)) { + console.warn("DetectorQueue was not set, detectors will not be fired"); + return; + } + var detectorCount = model.detectors.length; + for(var i = 0; i < detectorCount; i++) { + if(model.detectors[i].triggersOn(params.cfgkey)) { + (function (detector) { + model.detectorQueue.add(function() { + return detector.run(model, model.configID); + }); + })(model.detectors[i]); + } + } + }, + + /** + * @typedef {object} ConfigTestPayload + * @property {boolean} [isSuccess] + */ + + /** + * ConfigModel#configurationTested Event + * + * @event ConfigModel#configurationTested + * @type {ConfigTestPayload} + */ + + /** + * @typedef {object} StatusResponse + * @property {string} [status] + */ + + /** + * processes the ajax response of a configuration test request + * + * @param {ConfigModel} [model] + * @param {StatusResponse} [result] + * @fires ConfigModel#configurationTested + * @private + */ + _processTestResult: function(model, result) { + var payload = { + isSuccess: (result['status'] === 'success') + }; + model._broadcast('configurationTested', payload); + }, + + /** + * @typedef {object} BasicConfigPayload + * @property {boolean} [isSuccess] + * @property {string} [configPrefix] - the new config ID + * @property {string} [errorMessage] + */ + + /** + * ConfigModel#newConfiguration Event + * + * @event ConfigModel#newConfiguration + * @type {BasicConfigPayload} + */ + + /** + * @typedef {object} NewConfigResponse + * @property {string} [status] + * @property {string} [configPrefix] + * @property {object} [defaults] - default configuration values + * @property {string} [message] - might only appear with status being + * not 'success' + */ + + /** + * processes the ajax response of a new configuration request + * + * @param {ConfigModel} [model] + * @param {NewConfigResponse} [result] + * @param {boolean} [copyCurrent] + * @fires ConfigModel#newConfiguration + * @fires ConfigModel#configLoaded + * @private + */ + _processNewConfigPrefix: function(model, result, copyCurrent) { + var isSuccess = (result['status'] === 'success'); + var payload = { + isSuccess: isSuccess, + configPrefix: result['configPrefix'], + errorMessage: _.isUndefined(result['message']) ? '' : result['message'] + }; + model._broadcast('newConfiguration', payload); + + if(isSuccess) { + this.configID = result['configPrefix']; + if(!copyCurrent) { + model.configuration = {}; + $.each(result['defaults'], function(key, value) { + model.configuration[key] = value; + }); + // view / tabs need to update with new blank config + model._broadcast('configLoaded', model.configuration); + } + } + }, + + /** + * ConfigModel#deleteConfiguration Event + * + * @event ConfigModel#deleteConfiguration + * @type {BasicConfigPayload} + */ + + /** + * processes the ajax response of a delete configuration request + * + * @param {ConfigModel} [model] + * @param {StatusResponse} [result] + * @param {string} [configID] + * @fires ConfigModel#deleteConfiguration + * @private + */ + _processDeleteConfig: function(model, result, configID) { + var isSuccess = (result['status'] === 'success'); + var payload = { + isSuccess: isSuccess, + configPrefix: configID, + errorMessage: _.isUndefined(result['message']) ? '' : result['message'] + }; + model._broadcast('deleteConfiguration', payload); + } + }; + + OCA.LDAP.Wizard.ConfigModel = ConfigModel; +})(); diff --git a/apps/user_ldap/js/wizard/controller.js b/apps/user_ldap/js/wizard/controller.js new file mode 100644 index 00000000000..7c1f0d5d818 --- /dev/null +++ b/apps/user_ldap/js/wizard/controller.js @@ -0,0 +1,56 @@ +/** + * Copyright (c) 2015, Arthur Schiwon <blizzz@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or later. + * See the COPYING-README file. + */ + +OCA = OCA || {}; +OCA.LDAP = {}; +OCA.LDAP.Wizard = {}; + +(function(){ + + /** + * @classdesc minimalistic controller that basically makes the view render + * + * @constructor + */ + var WizardController = function() {}; + + WizardController.prototype = { + /** + * initializes the instance. Always call it after creating the instance. + */ + init: function() { + this.view = false; + this.configModel = false; + }, + + /** + * sets the model instance + * + * @param {OCA.LDAP.Wizard.ConfigModel} [model] + */ + setModel: function(model) { + this.configModel = model; + }, + + /** + * sets the view instance + * + * @param {OCA.LDAP.Wizard.WizardView} [view] + */ + setView: function(view) { + this.view = view; + }, + + /** + * makes the view render i.e. ready to be used + */ + run: function() { + this.view.render(); + } + }; + + OCA.LDAP.Wizard.Controller = WizardController; +})(); diff --git a/apps/user_ldap/js/wizard/view.js b/apps/user_ldap/js/wizard/view.js new file mode 100644 index 00000000000..8eb10c58017 --- /dev/null +++ b/apps/user_ldap/js/wizard/view.js @@ -0,0 +1,433 @@ +/** + * Copyright (c) 2015, Arthur Schiwon <blizzz@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or later. + * See the COPYING-README file. + */ + +OCA = OCA || {}; + +(function() { + + /** + * @classdesc main view class. It takes care of tab-unrelated control + * elements (status bar, control buttons) and does or requests configuration + * checks. It also manages the separate tab views. + * + * @constructor + */ + var WizardView = function() {}; + + WizardView.prototype = { + /** @constant {number} */ + STATUS_ERROR: 0, + /** @constant {number} */ + STATUS_INCOMPLETE: 1, + /** @constant {number} */ + STATUS_SUCCESS: 2, + + /** + * initializes the instance. Always call it after creating the instance. + */ + init: function () { + this.tabs = {}; + this.tabs.server = new OCA.LDAP.Wizard.WizardTabElementary(); + this.$settings = $('#ldapSettings'); + this.$saveSpinners = $('.ldap_saving'); + this.saveProcesses = 0; + _.bindAll(this, 'onTabChange', 'onTestButtonClick'); + }, + + /** + * applies click events to the forward and backword buttons + */ + initControls: function() { + var view = this; + $('.ldap_action_continue').click(function(event) { + event.preventDefault(); + view._controlContinue(view); + }); + + $('.ldap_action_back').click(function(event) { + event.preventDefault(); + view._controlBack(view); + }); + + $('.ldap_action_test_connection').click(this.onTestButtonClick); + }, + + /** + * registers a tab + * + * @param {OCA.LDAP.Wizard.WizardTabGeneric} tabView + * @param {string} index + * @returns {boolean} + */ + registerTab: function(tabView, index) { + if( _.isUndefined(this.tabs[index]) + && tabView instanceof OCA.LDAP.Wizard.WizardTabGeneric + ) { + this.tabs[index] = tabView; + this.tabs[index].setModel(this.configModel); + return true; + } + return false; + }, + + /** + * checks certain config values for completeness and depending on them + * enables or disables non-elementary tabs. + */ + basicStatusCheck: function(view) { + var host = view.configModel.configuration.ldap_host; + var port = view.configModel.configuration.ldap_port; + var base = view.configModel.configuration.ldap_base; + var agent = view.configModel.configuration.ldap_dn; + var pwd = view.configModel.configuration.ldap_agent_password; + + if((host && port && base) && ((!agent && !pwd) || (agent && pwd))) { + view.enableTabs(); + } else { + view.disableTabs(); + } + }, + + /** + * if the configuration is sufficient the model is being request to + * perform a configuration test. Otherwise, the status indicator is + * being updated with the status "incomplete" + */ + functionalityCheck: function() { + // this method should be called only if necessary, because it may + // cause an LDAP request! + var host = this.configModel.configuration.ldap_host; + var port = this.configModel.configuration.ldap_port; + var base = this.configModel.configuration.ldap_base; + var userFilter = this.configModel.configuration.ldap_userlist_filter; + var loginFilter = this.configModel.configuration.ldap_login_filter; + + if(host && port && base && userFilter && loginFilter) { + this.configModel.requestConfigurationTest(); + } else { + this._updateStatusIndicator(this.STATUS_INCOMPLETE); + } + }, + + /** + * will request a functionality check if one of the related configuration + * settings was changed. + * + * @param {ConfigSetPayload|Object} [changeSet] + */ + considerFunctionalityCheck: function(changeSet) { + var testTriggers = [ + 'ldap_host', 'ldap_port', 'ldap_dn', 'ldap_agent_password', + 'ldap_base', 'ldap_userlist_filter', 'ldap_login_filter' + ]; + for(var key in changeSet) { + if($.inArray(key, testTriggers)) { + this.functionalityCheck(); + return; + } + } + }, + + /** + * keeps number of running save processes and shows a spinner if + * necessary + * + * @param {WizardView} [view] + * @listens ConfigModel#setRequested + */ + onSetRequested: function(view) { + view.saveProcesses += 1; + if(view.saveProcesses === 1) { + view.showSaveSpinner(); + } + }, + + /** + * keeps number of running save processes and hides the spinner if + * necessary. Also triggers checks, to adjust tabs state and status bar. + * + * @param {WizardView} [view] + * @param {ConfigSetPayload} [result] + * @listens ConfigModel#setCompleted + */ + onSetRequestDone: function(view, result) { + if(view.saveProcesses > 0) { + view.saveProcesses -= 1; + if(view.saveProcesses === 0) { + view.hideSaveSpinner(); + } + } + + view.basicStatusCheck(view); + var param = {}; + param[result.key] = 1; + view.considerFunctionalityCheck(param); + }, + + /** + * updates the status indicator based on the configuration test result + * + * @param {WizardView} [view] + * @param {ConfigTestPayload} [result] + * @listens ConfigModel#configurationTested + */ + onTestCompleted: function(view, result) { + if(result.isSuccess) { + view._updateStatusIndicator(view.STATUS_SUCCESS); + } else { + view._updateStatusIndicator(view.STATUS_ERROR); + } + }, + + /** + * triggers initial checks upon configuration loading to update status + * controls + * + * @param {WizardView} [view] + * @listens ConfigModel#configLoaded + */ + onConfigLoaded: function(view) { + view.basicStatusCheck(view); + view.functionalityCheck(); + }, + + /** + * reacts on attempts to switch to a different tab + * + * @param {object} event + * @param {object} ui + * @returns {boolean} + */ + onTabChange: function(event, ui) { + if(this.saveProcesses > 0) { + return false; + } + + var newTabID = ui.newTab[0].id; + if(newTabID === '#ldapWizard1') { + newTabID = 'server'; + } + var oldTabID = ui.oldTab[0].id; + if(oldTabID === '#ldapWizard1') { + oldTabID = 'server'; + } + if(!_.isUndefined(this.tabs[newTabID])) { + this.tabs[newTabID].isActive = true; + this.tabs[newTabID].onActivate(); + } else { + console.warn('Unreferenced activated tab ' + newTabID); + } + if(!_.isUndefined(this.tabs[oldTabID])) { + this.tabs[oldTabID].isActive = false; + } else { + console.warn('Unreferenced left tab ' + oldTabID); + } + }, + + /** + * triggers checks upon configuration updates to keep status controls + * up to date + * + * @param {WizardView} [view] + * @param {object} [changeSet] + * @listens ConfigModel#configUpdated + */ + onConfigUpdated: function(view, changeSet) { + view.basicStatusCheck(view); + view.considerFunctionalityCheck(changeSet); + }, + + /** + * requests a configuration test + */ + onTestButtonClick: function() { + this.configModel.requestWizard('ldap_action_test_connection', this.configModel.configuration); + }, + + /** + * sets the model instance and registers event listeners + * + * @param {OCA.LDAP.Wizard.ConfigModel} [configModel] + */ + setModel: function(configModel) { + /** @type {OCA.LDAP.Wizard.ConfigModel} */ + this.configModel = configModel; + for(var i in this.tabs) { + this.tabs[i].setModel(configModel); + } + + // make sure this is definitely run after tabs did their work, order is important here + // for now this works, because tabs are supposed to register their listeners in their + // setModel() method. + // alternative: make Elementary Tab a Publisher as well. + this.configModel.on('configLoaded', this.onConfigLoaded, this); + this.configModel.on('configUpdated', this.onConfigUpdated, this); + this.configModel.on('setRequested', this.onSetRequested, this); + this.configModel.on('setCompleted', this.onSetRequestDone, this); + this.configModel.on('configurationTested', this.onTestCompleted, this); + }, + + /** + * enables tab and navigation buttons + */ + enableTabs: function() { + //do not use this function directly, use basicStatusCheck instead. + if(this.saveProcesses === 0) { + $('.ldap_action_continue').removeAttr('disabled'); + $('.ldap_action_back').removeAttr('disabled'); + this.$settings.tabs('option', 'disabled', []); + } + }, + + /** + * disables tab and navigation buttons + */ + disableTabs: function() { + $('.ldap_action_continue').attr('disabled', 'disabled'); + $('.ldap_action_back').attr('disabled', 'disabled'); + this.$settings.tabs('option', 'disabled', [1, 2, 3, 4, 5]); + }, + + /** + * shows a save spinner + */ + showSaveSpinner: function() { + this.$saveSpinners.removeClass('hidden'); + $('#ldap *').addClass('save-cursor'); + }, + + /** + * hides the save spinner + */ + hideSaveSpinner: function() { + this.$saveSpinners.addClass('hidden'); + $('#ldap *').removeClass('save-cursor'); + }, + + /** + * performs a config load request to the model + * + * @param {string} [configID] + * @private + */ + _requestConfig: function(configID) { + this.configModel.load(configID); + }, + + /** + * bootstraps the visual appearance and event listeners, as well as the + * first config + */ + render: function () { + $('#ldapAdvancedAccordion').accordion({ heightStyle: 'content', animate: 'easeInOutCirc'}); + this.$settings.tabs({}); + $('.ldap_submit').button(); + $('.ldap_action_test_connection').button(); + $('#ldapSettings').tabs({ beforeActivate: this.onTabChange }); + + this.initControls(); + this.disableTabs(); + + this._requestConfig(this.tabs.server.getConfigID()); + }, + + /** + * updates the status indicator / bar + * + * @param {number} [state] + * @private + */ + _updateStatusIndicator: function(state) { + var $indicator = $('.ldap_config_state_indicator'); + var $indicatorLight = $('.ldap_config_state_indicator_sign'); + + switch(state) { + case this.STATUS_ERROR: + $indicator.text(t('user_ldap', + 'Configuration incorrect' + )); + $indicator.removeClass('ldap_grey'); + $indicatorLight.addClass('error'); + $indicatorLight.removeClass('success'); + break; + case this.STATUS_INCOMPLETE: + $indicator.text(t('user_ldap', + 'Configuration incomplete' + )); + $indicator.removeClass('ldap_grey'); + $indicatorLight.removeClass('error'); + $indicatorLight.removeClass('success'); + break; + case this.STATUS_SUCCESS: + $indicator.text(t('user_ldap', 'Configuration OK')); + $indicator.addClass('ldap_grey'); + $indicatorLight.removeClass('error'); + $indicatorLight.addClass('success'); + if(!this.tabs.server.isActive) { + this.configModel.set('ldap_configuration_active', 1); + } + break; + } + }, + + /** + * handles a click on the Back button + * + * @param {WizardView} [view] + * @private + */ + _controlBack: function(view) { + var curTabIndex = view.$settings.tabs('option', 'active'); + if(curTabIndex == 0) { + return; + } + view.$settings.tabs('option', 'active', curTabIndex - 1); + view._controlUpdate(curTabIndex - 1); + }, + + /** + * handles a click on the Continue button + * + * @param {WizardView} [view] + * @private + */ + _controlContinue: function(view) { + var curTabIndex = view.$settings.tabs('option', 'active'); + if(curTabIndex == 3) { + return; + } + view.$settings.tabs('option', 'active', 1 + curTabIndex); + view._controlUpdate(curTabIndex + 1); + }, + + /** + * updates the controls (navigation buttons) + * + * @param {number} [nextTabIndex] - index of the tab being switched to + * @private + */ + _controlUpdate: function(nextTabIndex) { + if(nextTabIndex == 0) { + $('.ldap_action_back').addClass('invisible'); + $('.ldap_action_continue').removeClass('invisible'); + } else + if(nextTabIndex == 1) { + $('.ldap_action_back').removeClass('invisible'); + $('.ldap_action_continue').removeClass('invisible'); + } else + if(nextTabIndex == 2) { + $('.ldap_action_continue').removeClass('invisible'); + $('.ldap_action_back').removeClass('invisible'); + } else + if(nextTabIndex == 3) { + $('.ldap_action_back').removeClass('invisible'); + $('.ldap_action_continue').addClass('invisible'); + } + } + }; + + OCA.LDAP.Wizard.WizardView = WizardView; +})(); diff --git a/apps/user_ldap/js/wizard/wizard.js b/apps/user_ldap/js/wizard/wizard.js new file mode 100644 index 00000000000..faa9de918a4 --- /dev/null +++ b/apps/user_ldap/js/wizard/wizard.js @@ -0,0 +1,80 @@ +/** + * Copyright (c) 2015, Arthur Schiwon <blizzz@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or later. + * See the COPYING-README file. + */ + +OCA = OCA || {}; + + + +/** + * initializes the wizard and related components and kicks it off. + */ + +(function() { + var Wizard = function() { + var detectorQueue = new OCA.LDAP.Wizard.WizardDetectorQueue(); + detectorQueue.init(); + + var detectors = []; + detectors.push(new OCA.LDAP.Wizard.WizardDetectorPort()); + detectors.push(new OCA.LDAP.Wizard.WizardDetectorBaseDN()); + detectors.push(new OCA.LDAP.Wizard.WizardDetectorEmailAttribute()); + detectors.push(new OCA.LDAP.Wizard.WizardDetectorUserDisplayNameAttribute()); + detectors.push(new OCA.LDAP.Wizard.WizardDetectorUserGroupAssociation()); + detectors.push(new OCA.LDAP.Wizard.WizardDetectorUserObjectClasses()); + detectors.push(new OCA.LDAP.Wizard.WizardDetectorGroupObjectClasses()); + detectors.push(new OCA.LDAP.Wizard.WizardDetectorGroupsForUsers()); + detectors.push(new OCA.LDAP.Wizard.WizardDetectorGroupsForGroups()); + detectors.push(new OCA.LDAP.Wizard.WizardDetectorFilterUser()); + detectors.push(new OCA.LDAP.Wizard.WizardDetectorFilterLogin()); + detectors.push(new OCA.LDAP.Wizard.WizardDetectorFilterGroup()); + detectors.push(new OCA.LDAP.Wizard.WizardDetectorUserCount()); + detectors.push(new OCA.LDAP.Wizard.WizardDetectorGroupCount()); + detectors.push(new OCA.LDAP.Wizard.WizardDetectorAvailableAttributes()); + detectors.push(new OCA.LDAP.Wizard.WizardDetectorTestLoginName()); + detectors.push(new OCA.LDAP.Wizard.WizardDetectorTestBaseDN()); + detectors.push(new OCA.LDAP.Wizard.WizardDetectorTestConfiguration()); + detectors.push(new OCA.LDAP.Wizard.WizardDetectorClearUserMappings()); + detectors.push(new OCA.LDAP.Wizard.WizardDetectorClearGroupMappings()); + + var model = new OCA.LDAP.Wizard.ConfigModel(); + model.init(detectorQueue); + // NOTE: order of detectors may play a role + // for example, BaseDN detector needs the port. The port is typically found + // by the Port Detector. If BaseDN detector was run first, it will not have + // all necessary information. Only after Port Detector was executed… + for (var i = 0; i <= detectors.length; i++) { + model.registerDetector(detectors[i]); + } + + var filterOnTypeFactory = new OCA.LDAP.Wizard.FilterOnTypeFactory(); + + var tabs = []; + tabs.push(new OCA.LDAP.Wizard.WizardTabUserFilter(filterOnTypeFactory)); + tabs.push(new OCA.LDAP.Wizard.WizardTabLoginFilter()); + tabs.push(new OCA.LDAP.Wizard.WizardTabGroupFilter(filterOnTypeFactory)); + tabs.push(new OCA.LDAP.Wizard.WizardTabAdvanced()); + tabs.push(new OCA.LDAP.Wizard.WizardTabExpert()); + + var view = new OCA.LDAP.Wizard.WizardView(model); + view.init(); + view.setModel(model); + for (var j = 0; j <= tabs.length; j++) { + view.registerTab(tabs[j], '#ldapWizard' + (j + 2)); + } + + var controller = new OCA.LDAP.Wizard.Controller(); + controller.init(); + controller.setView(view); + controller.setModel(model); + controller.run(); + } + + OCA.LDAP.Wizard.Wizard = Wizard; +})(); + +$(document).ready(function() { + new OCA.LDAP.Wizard.Wizard(); +}); diff --git a/apps/user_ldap/js/wizard/wizardDetectorAvailableAttributes.js b/apps/user_ldap/js/wizard/wizardDetectorAvailableAttributes.js new file mode 100644 index 00000000000..f0272351749 --- /dev/null +++ b/apps/user_ldap/js/wizard/wizardDetectorAvailableAttributes.js @@ -0,0 +1,59 @@ + +/** + * Copyright (c) 2015, Arthur Schiwon <blizzz@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or later. + * See the COPYING-README file. + */ + +OCA = OCA || {}; + +(function() { + + /** + * @classdesc an Attributes Detector. It executes the auto-detection of + * available attributes by the ownCloud server, if requirements are met. + * + * @constructor + */ + var WizardDetectorAvailableAttributes = OCA.LDAP.Wizard.WizardDetectorGeneric.subClass({ + /** @inheritdoc */ + init: function() { + // given, it is not a configuration key + this.setTargetKey('ldap_loginfilter_attributes'); + this.runsOnRequest = true; + }, + + /** + * runs the detector, if port is not set. + * + * @param {OCA.LDAP.Wizard.ConfigModel} model + * @param {string} configID - the configuration prefix + * @returns {boolean|jqXHR} + * @abstract + */ + run: function(model, configID) { + model.notifyAboutDetectionStart(this.getTargetKey()); + var params = OC.buildQueryString({ + action: 'determineAttributes', + ldap_serverconfig_chooser: configID + }); + return model.callWizard(params, this.processResult, this); + }, + + /** + * @inheritdoc + */ + processResult: function(model, detector, result) { + if(result.status === 'success') { + var payload = { + feature: 'AvailableAttributes', + data: result.options[detector.getTargetKey()] + }; + model.inform(payload); + } + this._super(model, detector, result); + } + }); + + OCA.LDAP.Wizard.WizardDetectorAvailableAttributes = WizardDetectorAvailableAttributes; +})(); diff --git a/apps/user_ldap/js/wizard/wizardDetectorBaseDN.js b/apps/user_ldap/js/wizard/wizardDetectorBaseDN.js new file mode 100644 index 00000000000..70b9923e58d --- /dev/null +++ b/apps/user_ldap/js/wizard/wizardDetectorBaseDN.js @@ -0,0 +1,52 @@ + +/** + * Copyright (c) 2015, Arthur Schiwon <blizzz@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or later. + * See the COPYING-README file. + */ + +OCA = OCA || {}; + +(function() { + + /** + * @classdesc a Base DN Detector. It executes the auto-detection of the base + * DN by the ownCloud server, if requirements are met. + * + * @constructor + */ + var WizardDetectorBaseDN = OCA.LDAP.Wizard.WizardDetectorGeneric.subClass({ + /** @inheritdoc */ + init: function() { + this.setTargetKey('ldap_base'); + this.runsOnRequest = true; + }, + + /** + * runs the detector, if specified configuration settings are set and + * base DN is not set. + * + * @param {OCA.LDAP.Wizard.ConfigModel} model + * @param {string} configID - the configuration prefix + * @returns {boolean|jqXHR} + * @abstract + */ + run: function(model, configID) { + if( !model.configuration['ldap_host'] + || !model.configuration['ldap_port'] + + ) + { + return false; + } + model.notifyAboutDetectionStart(this.getTargetKey()); + var params = OC.buildQueryString({ + action: 'guessBaseDN', + ldap_serverconfig_chooser: configID + }); + return model.callWizard(params, this.processResult, this); + } + }); + + OCA.LDAP.Wizard.WizardDetectorBaseDN = WizardDetectorBaseDN; +})(); diff --git a/apps/user_ldap/js/wizard/wizardDetectorClearGroupMappings.js b/apps/user_ldap/js/wizard/wizardDetectorClearGroupMappings.js new file mode 100644 index 00000000000..c6ef0a9cab1 --- /dev/null +++ b/apps/user_ldap/js/wizard/wizardDetectorClearGroupMappings.js @@ -0,0 +1,30 @@ + +/** + * Copyright (c) 2015, Arthur Schiwon <blizzz@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or later. + * See the COPYING-README file. + */ + +OCA = OCA || {}; + +(function() { + + /** + * @classdesc requests clearing of user mappings + * + * @constructor + */ + var WizardDetectorClearGroupMappings = OCA.LDAP.Wizard.WizardDetectorTestAbstract.subClass({ + /** @inheritdoc */ + init: function() { + // given, it is not a configuration key + this.setTargetKey('ldap_action_clear_group_mappings'); + this.testName = 'ClearMappings'; + this.isLegacy = true; + this.legacyDestination = 'clearMappings.php'; + this.runsOnRequest = true; + } + }); + + OCA.LDAP.Wizard.WizardDetectorClearGroupMappings = WizardDetectorClearGroupMappings; +})(); diff --git a/apps/user_ldap/js/wizard/wizardDetectorClearUserMappings.js b/apps/user_ldap/js/wizard/wizardDetectorClearUserMappings.js new file mode 100644 index 00000000000..0e4811b39ea --- /dev/null +++ b/apps/user_ldap/js/wizard/wizardDetectorClearUserMappings.js @@ -0,0 +1,30 @@ + +/** + * Copyright (c) 2015, Arthur Schiwon <blizzz@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or later. + * See the COPYING-README file. + */ + +OCA = OCA || {}; + +(function() { + + /** + * @classdesc requests clearing of user mappings + * + * @constructor + */ + var WizardDetectorClearUserMappings = OCA.LDAP.Wizard.WizardDetectorTestAbstract.subClass({ + /** @inheritdoc */ + init: function() { + // given, it is not a configuration key + this.setTargetKey('ldap_action_clear_user_mappings'); + this.testName = 'ClearMappings'; + this.isLegacy = true; + this.legacyDestination = 'clearMappings.php'; + this.runsOnRequest = true; + } + }); + + OCA.LDAP.Wizard.WizardDetectorClearUserMappings = WizardDetectorClearUserMappings; +})(); diff --git a/apps/user_ldap/js/wizard/wizardDetectorEmailAttribute.js b/apps/user_ldap/js/wizard/wizardDetectorEmailAttribute.js new file mode 100644 index 00000000000..5f177734681 --- /dev/null +++ b/apps/user_ldap/js/wizard/wizardDetectorEmailAttribute.js @@ -0,0 +1,38 @@ + +/** + * Copyright (c) 2015, Arthur Schiwon <blizzz@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or later. + * See the COPYING-README file. + */ + +OCA = OCA || {}; + +(function() { + + /** + * @classdesc let's the wizard backend count the available users + * + * @constructor + */ + var WizardDetectorEmailAttribute = OCA.LDAP.Wizard.WizardDetectorFilterSimpleRequestAbstract.subClass({ + init: function() { + this.setTargetKey('ldap_user_count'); + this.wizardMethod = 'detectEmailAttribute'; + this.runsOnRequest = true; + }, + + /** + * @inheritdoc + */ + run: function(model, configID) { + if(model.configuration.ldap_email_attr) { + // a value is already set. Don't overwrite and don't ask LDAP + // without reason. + return false; + } + this._super(model, configID); + } + }); + + OCA.LDAP.Wizard.WizardDetectorEmailAttribute = WizardDetectorEmailAttribute; +})(); diff --git a/apps/user_ldap/js/wizard/wizardDetectorFeatureAbstract.js b/apps/user_ldap/js/wizard/wizardDetectorFeatureAbstract.js new file mode 100644 index 00000000000..e025d8d6242 --- /dev/null +++ b/apps/user_ldap/js/wizard/wizardDetectorFeatureAbstract.js @@ -0,0 +1,52 @@ + +/** + * Copyright (c) 2015, Arthur Schiwon <blizzz@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or later. + * See the COPYING-README file. + */ + +OCA = OCA || {}; + +(function() { + + /** + * @classdesc abstract detector for detecting groups and object classes + * + * @constructor + */ + var WizardDetectorFeatureAbstract = OCA.LDAP.Wizard.WizardDetectorGeneric.subClass({ + /** + * runs the detector, if port is not set. + * + * @param {OCA.LDAP.Wizard.ConfigModel} model + * @param {string} configID - the configuration prefix + * @returns {boolean|jqXHR} + * @abstract + */ + run: function(model, configID) { + model.notifyAboutDetectionStart(this.getTargetKey()); + var params = OC.buildQueryString({ + action: this.wizardMethod, + ldap_serverconfig_chooser: configID + }); + return model.callWizard(params, this.processResult, this); + }, + + /** + * @inheritdoc + */ + processResult: function(model, detector, result) { + if(result.status === 'success') { + var payload = { + feature: detector.featureName, + data: result.options[detector.getTargetKey()] + }; + model.inform(payload); + } + + this._super(model, detector, result); + } + }); + + OCA.LDAP.Wizard.WizardDetectorFeatureAbstract = WizardDetectorFeatureAbstract; +})(); diff --git a/apps/user_ldap/js/wizard/wizardDetectorFilterGroup.js b/apps/user_ldap/js/wizard/wizardDetectorFilterGroup.js new file mode 100644 index 00000000000..cca889839e4 --- /dev/null +++ b/apps/user_ldap/js/wizard/wizardDetectorFilterGroup.js @@ -0,0 +1,31 @@ + +/** + * Copyright (c) 2015, Arthur Schiwon <blizzz@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or later. + * See the COPYING-README file. + */ + +OCA = OCA || {}; + +(function() { + + /** + * @classdesc a Port Detector. It executes the auto-detection of the port + * by the ownCloud server, if requirements are met. + * + * @constructor + */ + var WizardDetectorFilterGroup = OCA.LDAP.Wizard.WizardDetectorFilterSimpleRequestAbstract.subClass({ + init: function() { + this.setTrigger([ + 'ldap_groupfilter_groups', + 'ldap_groupfilter_objectclass' + ]); + this.setTargetKey('ldap_group_filter'); + + this.wizardMethod = 'getGroupFilter'; + } + }); + + OCA.LDAP.Wizard.WizardDetectorFilterGroup = WizardDetectorFilterGroup; +})(); diff --git a/apps/user_ldap/js/wizard/wizardDetectorFilterLogin.js b/apps/user_ldap/js/wizard/wizardDetectorFilterLogin.js new file mode 100644 index 00000000000..310f261e05e --- /dev/null +++ b/apps/user_ldap/js/wizard/wizardDetectorFilterLogin.js @@ -0,0 +1,32 @@ + +/** + * Copyright (c) 2015, Arthur Schiwon <blizzz@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or later. + * See the COPYING-README file. + */ + +OCA = OCA || {}; + +(function() { + + /** + * @classdesc a Port Detector. It executes the auto-detection of the port + * by the ownCloud server, if requirements are met. + * + * @constructor + */ + var WizardDetectorFilterLogin = OCA.LDAP.Wizard.WizardDetectorFilterSimpleRequestAbstract.subClass({ + init: function() { + this.setTrigger([ + 'ldap_loginfilter_username', + 'ldap_loginfilter_email', + 'ldap_loginfilter_attributes' + ]); + this.setTargetKey('ldap_login_filter'); + + this.wizardMethod = 'getUserLoginFilter'; + } + }); + + OCA.LDAP.Wizard.WizardDetectorFilterLogin = WizardDetectorFilterLogin; +})(); diff --git a/apps/user_ldap/js/wizard/wizardDetectorFilterUser.js b/apps/user_ldap/js/wizard/wizardDetectorFilterUser.js new file mode 100644 index 00000000000..63dff4e2985 --- /dev/null +++ b/apps/user_ldap/js/wizard/wizardDetectorFilterUser.js @@ -0,0 +1,31 @@ + +/** + * Copyright (c) 2015, Arthur Schiwon <blizzz@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or later. + * See the COPYING-README file. + */ + +OCA = OCA || {}; + +(function() { + + /** + * @classdesc a Port Detector. It executes the auto-detection of the port + * by the ownCloud server, if requirements are met. + * + * @constructor + */ + var WizardDetectorFilterUser = OCA.LDAP.Wizard.WizardDetectorFilterSimpleRequestAbstract.subClass({ + init: function() { + this.setTrigger([ + 'ldap_userfilter_groups', + 'ldap_userfilter_objectclass' + ]); + this.setTargetKey('ldap_userlist_filter'); + + this.wizardMethod = 'getUserListFilter'; + } + }); + + OCA.LDAP.Wizard.WizardDetectorFilterUser = WizardDetectorFilterUser; +})(); diff --git a/apps/user_ldap/js/wizard/wizardDetectorGeneric.js b/apps/user_ldap/js/wizard/wizardDetectorGeneric.js new file mode 100644 index 00000000000..fd80018943e --- /dev/null +++ b/apps/user_ldap/js/wizard/wizardDetectorGeneric.js @@ -0,0 +1,117 @@ + +/** + * Copyright (c) 2015, Arthur Schiwon <blizzz@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or later. + * See the COPYING-README file. + */ + +OCA = OCA || {}; + +(function() { + /** + * @classdesc a generic (abstract) Detector template. A Detector's task is + * to kick off server side detection of certain LDAP features. It is invoked + * when changes to specified configuration keys happen. + * + * @constructor + */ + var WizardDetectorGeneric = OCA.LDAP.Wizard.WizardObject.subClass({ + /** + * initializes the instance. Always call it after creating the instance. + */ + init: function() { + this.setTrigger([]); + this.targetKey = ''; + this.runsOnRequest = false; + }, + + /** + * sets the configuration keys the detector is listening on + * + * @param {string[]} triggers + */ + setTrigger: function(triggers) { + this.triggers = triggers; + }, + + /** + * tests whether the detector is triggered by the provided key + * + * @param {string} key + * @returns {boolean} + */ + triggersOn: function(key) { + return ($.inArray(key, this.triggers) >= 0); + }, + + /** + * whether the detector runs on explicit request + * + * @param {string} key + * @returns {boolean} + */ + runsOnFeatureRequest: function(key) { + return !!(this.runsOnRequest && this.targetKey === key); + }, + + /** + * sets the configuration key the detector is attempting to auto-detect + * + * @param {string} key + */ + setTargetKey: function(key) { + this.targetKey = key; + }, + + /** + * returns the configuration key the detector is attempting to + * auto-detect + */ + getTargetKey: function() { + return this.targetKey; + }, + + /** + * runs the detector. This method is supposed to be implemented by the + * concrete detector. + * + * Must return false if the detector decides not to run. + * Must return a jqXHR object otherwise, which is provided by the + * model's callWizard() + * + * @param {OCA.LDAP.Wizard.ConfigModel} model + * @param {string} configID - the configuration prefix + * @returns {boolean|jqXHR} + * @abstract + */ + run: function(model, configID) { + // to be implemented by subClass + return false; + }, + + /** + * processes the result of the ownCloud server + * + * @param {OCA.LDAP.Wizard.ConfigModel} model + * @param {WizardDetectorGeneric} detector + * @param {object} result + */ + processResult: function(model, detector, result) { + model['notifyAboutDetectionCompletion'](detector.getTargetKey()); + if(result.status === 'success') { + for (var id in result.changes) { + // update and not set method, as values are already stored + model['update'](id, result.changes[id]); + } + } else { + var payload = { relatedKey: detector.targetKey }; + if(!_.isUndefined(result.message)) { + payload.message = result.message; + } + model.gotServerError(payload); + } + } + }); + + OCA.LDAP.Wizard.WizardDetectorGeneric = WizardDetectorGeneric; +})(); diff --git a/apps/user_ldap/js/wizard/wizardDetectorGroupCount.js b/apps/user_ldap/js/wizard/wizardDetectorGroupCount.js new file mode 100644 index 00000000000..12d7df7514b --- /dev/null +++ b/apps/user_ldap/js/wizard/wizardDetectorGroupCount.js @@ -0,0 +1,27 @@ + +/** + * Copyright (c) 2015, Arthur Schiwon <blizzz@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or later. + * See the COPYING-README file. + */ + +OCA = OCA || {}; + +(function() { + + /** + * @classdesc a Port Detector. It executes the auto-detection of the port + * by the ownCloud server, if requirements are met. + * + * @constructor + */ + var WizardDetectorGroupCount = OCA.LDAP.Wizard.WizardDetectorFilterSimpleRequestAbstract.subClass({ + init: function() { + this.setTargetKey('ldap_group_count'); + this.wizardMethod = 'countGroups'; + this.runsOnRequest = true; + } + }); + + OCA.LDAP.Wizard.WizardDetectorGroupCount = WizardDetectorGroupCount; +})(); diff --git a/apps/user_ldap/js/wizard/wizardDetectorGroupObjectClasses.js b/apps/user_ldap/js/wizard/wizardDetectorGroupObjectClasses.js new file mode 100644 index 00000000000..6d6048b7986 --- /dev/null +++ b/apps/user_ldap/js/wizard/wizardDetectorGroupObjectClasses.js @@ -0,0 +1,29 @@ + +/** + * Copyright (c) 2015, Arthur Schiwon <blizzz@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or later. + * See the COPYING-README file. + */ + +OCA = OCA || {}; + +(function() { + + /** + * @classdesc discovers object classes for the groups tab + * + * @constructor + */ + var WizardDetectorGroupObjectClasses = OCA.LDAP.Wizard.WizardDetectorFeatureAbstract.subClass({ + /** @inheritdoc */ + init: function() { + // given, it is not a configuration key + this.setTargetKey('ldap_groupfilter_objectclass'); + this.wizardMethod = 'determineGroupObjectClasses'; + this.featureName = 'GroupObjectClasses'; + this.runsOnRequest = true; + } + }); + + OCA.LDAP.Wizard.WizardDetectorGroupObjectClasses = WizardDetectorGroupObjectClasses; +})(); diff --git a/apps/user_ldap/js/wizard/wizardDetectorGroupsForGroups.js b/apps/user_ldap/js/wizard/wizardDetectorGroupsForGroups.js new file mode 100644 index 00000000000..fbb3f02e10a --- /dev/null +++ b/apps/user_ldap/js/wizard/wizardDetectorGroupsForGroups.js @@ -0,0 +1,29 @@ + +/** + * Copyright (c) 2015, Arthur Schiwon <blizzz@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or later. + * See the COPYING-README file. + */ + +OCA = OCA || {}; + +(function() { + + /** + * @classdesc detects groups for the groups tab + * + * @constructor + */ + var WizardDetectorGroupsForGroups = OCA.LDAP.Wizard.WizardDetectorFeatureAbstract.subClass({ + /** @inheritdoc */ + init: function() { + // given, it is not a configuration key + this.setTargetKey('ldap_groupfilter_groups'); + this.wizardMethod = 'determineGroupsForGroups'; + this.featureName = 'GroupsForGroups'; + this.runsOnRequest = true; + } + }); + + OCA.LDAP.Wizard.WizardDetectorGroupsForGroups = WizardDetectorGroupsForGroups; +})(); diff --git a/apps/user_ldap/js/wizard/wizardDetectorGroupsForUsers.js b/apps/user_ldap/js/wizard/wizardDetectorGroupsForUsers.js new file mode 100644 index 00000000000..fe67854c794 --- /dev/null +++ b/apps/user_ldap/js/wizard/wizardDetectorGroupsForUsers.js @@ -0,0 +1,29 @@ + +/** + * Copyright (c) 2015, Arthur Schiwon <blizzz@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or later. + * See the COPYING-README file. + */ + +OCA = OCA || {}; + +(function() { + + /** + * @classdesc detects groups for the users tab + * + * @constructor + */ + var WizardDetectorGroupsForUsers = OCA.LDAP.Wizard.WizardDetectorFeatureAbstract.subClass({ + /** @inheritdoc */ + init: function() { + // given, it is not a configuration key + this.setTargetKey('ldap_userfilter_groups'); + this.wizardMethod = 'determineGroupsForUsers'; + this.featureName = 'GroupsForUsers'; + this.runsOnRequest = true; + } + }); + + OCA.LDAP.Wizard.WizardDetectorGroupsForUsers = WizardDetectorGroupsForUsers; +})(); diff --git a/apps/user_ldap/js/wizard/wizardDetectorPort.js b/apps/user_ldap/js/wizard/wizardDetectorPort.js new file mode 100644 index 00000000000..ba075189667 --- /dev/null +++ b/apps/user_ldap/js/wizard/wizardDetectorPort.js @@ -0,0 +1,44 @@ + +/** + * Copyright (c) 2015, Arthur Schiwon <blizzz@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or later. + * See the COPYING-README file. + */ + +OCA = OCA || {}; + +(function() { + + /** + * @classdesc a Port Detector. It executes the auto-detection of the port + * by the ownCloud server, if requirements are met. + * + * @constructor + */ + var WizardDetectorPort = OCA.LDAP.Wizard.WizardDetectorGeneric.subClass({ + /** @inheritdoc */ + init: function() { + this.setTargetKey('ldap_port'); + this.runsOnRequest = true; + }, + + /** + * runs the detector, if port is not set. + * + * @param {OCA.LDAP.Wizard.ConfigModel} model + * @param {string} configID - the configuration prefix + * @returns {boolean|jqXHR} + * @abstract + */ + run: function(model, configID) { + model.notifyAboutDetectionStart('ldap_port'); + var params = OC.buildQueryString({ + action: 'guessPortAndTLS', + ldap_serverconfig_chooser: configID + }); + return model.callWizard(params, this.processResult, this); + } + }); + + OCA.LDAP.Wizard.WizardDetectorPort = WizardDetectorPort; +})(); diff --git a/apps/user_ldap/js/wizard/wizardDetectorQueue.js b/apps/user_ldap/js/wizard/wizardDetectorQueue.js new file mode 100644 index 00000000000..448dfc18036 --- /dev/null +++ b/apps/user_ldap/js/wizard/wizardDetectorQueue.js @@ -0,0 +1,89 @@ + +/** + * Copyright (c) 2015, Arthur Schiwon <blizzz@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or later. + * See the COPYING-README file. + */ + +OCA = OCA || {}; + +(function() { + /** + * @classdesc only run detector is allowed to run at a time. Basically + * because we cannot have parallel LDAP connections per session. This + * queue is takes care of running all the detectors one after the other. + * + * @constructor + */ + var WizardDetectorQueue = OCA.LDAP.Wizard.WizardObject.subClass({ + /** + * initializes the instance. Always call it after creating the instance. + */ + init: function() { + this.queue = []; + this.isRunning = false; + }, + + /** + * empties the queue and cancels a possibly running request + */ + reset: function() { + this.queue = []; + if(!_.isUndefined(this.runningRequest)) { + this.runningRequest.abort(); + delete this.runningRequest; + } + this.isRunning = false; + }, + + /** + * a parameter-free callback that eventually executes the run method of + * the detector. + * + * @callback detectorCallBack + * @see OCA.LDAP.Wizard.ConfigModel._processSetResult + */ + + /** + * adds a detector to the queue and attempts to trigger to run the + * next job, because it might be the first. + * + * @param {detectorCallBack} callback + */ + add: function(callback) { + this.queue.push(callback); + this.next(); + }, + + /** + * Executes the next detector if none is running. This method is also + * automatically invoked after a detector finished. + */ + next: function() { + if(this.isRunning === true || this.queue.length === 0) { + return; + } + + this.isRunning = true; + var callback = this.queue.shift(); + var request = callback(); + + // we receive either false or a jqXHR object + // false in case the detector decided against executing + if(request === false) { + this.isRunning = false; + this.next(); + return; + } + this.runningRequest = request; + + var detectorQueue = this; + $.when(request).then(function() { + detectorQueue.isRunning = false; + detectorQueue.next(); + }); + } + }); + + OCA.LDAP.Wizard.WizardDetectorQueue = WizardDetectorQueue; +})();
\ No newline at end of file diff --git a/apps/user_ldap/js/wizard/wizardDetectorSimpleRequestAbstract.js b/apps/user_ldap/js/wizard/wizardDetectorSimpleRequestAbstract.js new file mode 100644 index 00000000000..37e41f42a64 --- /dev/null +++ b/apps/user_ldap/js/wizard/wizardDetectorSimpleRequestAbstract.js @@ -0,0 +1,44 @@ + +/** + * Copyright (c) 2015, Arthur Schiwon <blizzz@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or later. + * See the COPYING-README file. + */ + +OCA = OCA || {}; + +(function() { + + /** + * @classdesc a Port Detector. It executes the auto-detection of the port + * by the ownCloud server, if requirements are met. + * + * @constructor + */ + var WizardDetectorFilterSimpleRequestAbstract = OCA.LDAP.Wizard.WizardDetectorGeneric.subClass({ + runsOnRequest: true, + + /** + * runs the detector, if port is not set. + * + * @param {OCA.LDAP.Wizard.ConfigModel} model + * @param {string} configID - the configuration prefix + * @returns {boolean|jqXHR} + * @abstract + */ + run: function(model, configID) { + if(_.isUndefined(this.wizardMethod)) { + console.warn('wizardMethod not set! ' + this.constructor); + return false; + } + model.notifyAboutDetectionStart(this.targetKey); + var params = OC.buildQueryString({ + action: this.wizardMethod, + ldap_serverconfig_chooser: configID + }); + return model.callWizard(params, this.processResult, this); + } + }); + + OCA.LDAP.Wizard.WizardDetectorFilterSimpleRequestAbstract = WizardDetectorFilterSimpleRequestAbstract; +})(); diff --git a/apps/user_ldap/js/wizard/wizardDetectorTestAbstract.js b/apps/user_ldap/js/wizard/wizardDetectorTestAbstract.js new file mode 100644 index 00000000000..df0b0a2200a --- /dev/null +++ b/apps/user_ldap/js/wizard/wizardDetectorTestAbstract.js @@ -0,0 +1,63 @@ + +/** + * Copyright (c) 2015, Arthur Schiwon <blizzz@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or later. + * See the COPYING-README file. + */ + +OCA = OCA || {}; + +(function() { + + /** + * @classdesc a Port Detector. It executes the auto-detection of the port + * by the ownCloud server, if requirements are met. + * + * @constructor + */ + var WizardDetectorTestAbstract = OCA.LDAP.Wizard.WizardDetectorGeneric.subClass({ + isLegacy: false, + + /** + * runs the test + * + * @param {OCA.LDAP.Wizard.ConfigModel} model + * @param {string} configID - the configuration prefix + * @param {Object} params - additional parameters needed to send to the + * wizard + * @returns {boolean|jqXHR} + * @abstract + */ + run: function(model, configID, params) { + if(_.isUndefined(this.wizardMethod) && !this.isLegacy) { + console.warn('wizardMethod not set! ' + this.constructor); + return false; + } + model.notifyAboutDetectionStart(this.getTargetKey()); + params = params || {}; + params = OC.buildQueryString($.extend({ + action: this.wizardMethod, + ldap_serverconfig_chooser: configID + }, params)); + if(!this.isLegacy) { + return model.callWizard(params, this.processResult, this); + } else { + return model.callAjax(this.legacyDestination, params, this.processResult, this); + } + }, + + /** + * @inheritdoc + */ + processResult: function(model, detector, result) { + model['notifyAboutDetectionCompletion'](detector.getTargetKey()); + var payload = { + feature: detector.testName, + data: result + }; + model.inform(payload); + } + }); + + OCA.LDAP.Wizard.WizardDetectorTestAbstract = WizardDetectorTestAbstract; +})(); diff --git a/apps/user_ldap/js/wizard/wizardDetectorTestBaseDN.js b/apps/user_ldap/js/wizard/wizardDetectorTestBaseDN.js new file mode 100644 index 00000000000..52848819bd8 --- /dev/null +++ b/apps/user_ldap/js/wizard/wizardDetectorTestBaseDN.js @@ -0,0 +1,29 @@ + +/** + * Copyright (c) 2015, Arthur Schiwon <blizzz@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or later. + * See the COPYING-README file. + */ + +OCA = OCA || {}; + +(function() { + + /** + * @classdesc Tests, how many objects reside in the given base DN(s) + * + * @constructor + */ + var WizardDetectorTestBaseDN = OCA.LDAP.Wizard.WizardDetectorTestAbstract.subClass({ + /** @inheritdoc */ + init: function() { + // given, it is not a configuration key + this.setTargetKey('ldap_test_base'); + this.testName = 'TestBaseDN'; + this.wizardMethod = 'countInBaseDN'; + this.runsOnRequest = true; + } + }); + + OCA.LDAP.Wizard.WizardDetectorTestBaseDN = WizardDetectorTestBaseDN; +})(); diff --git a/apps/user_ldap/js/wizard/wizardDetectorTestConfiguration.js b/apps/user_ldap/js/wizard/wizardDetectorTestConfiguration.js new file mode 100644 index 00000000000..1308c182909 --- /dev/null +++ b/apps/user_ldap/js/wizard/wizardDetectorTestConfiguration.js @@ -0,0 +1,31 @@ + +/** + * Copyright (c) 2015, Arthur Schiwon <blizzz@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or later. + * See the COPYING-README file. + */ + +OCA = OCA || {}; + +(function() { + + /** + * @classdesc a Port Detector. It executes the auto-detection of the port + * by the ownCloud server, if requirements are met. + * + * @constructor + */ + var WizardDetectorTestConfiguration = OCA.LDAP.Wizard.WizardDetectorTestAbstract.subClass({ + /** @inheritdoc */ + init: function() { + // given, it is not a configuration key + this.setTargetKey('ldap_action_test_connection'); + this.testName = 'TestConfiguration'; + this.isLegacy = true; + this.legacyDestination = 'testConfiguration.php'; + this.runsOnRequest = true; + } + }); + + OCA.LDAP.Wizard.WizardDetectorTestConfiguration = WizardDetectorTestConfiguration; +})(); diff --git a/apps/user_ldap/js/wizard/wizardDetectorTestLoginName.js b/apps/user_ldap/js/wizard/wizardDetectorTestLoginName.js new file mode 100644 index 00000000000..cf992df43b3 --- /dev/null +++ b/apps/user_ldap/js/wizard/wizardDetectorTestLoginName.js @@ -0,0 +1,30 @@ + +/** + * Copyright (c) 2015, Arthur Schiwon <blizzz@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or later. + * See the COPYING-README file. + */ + +OCA = OCA || {}; + +(function() { + + /** + * @classdesc a Port Detector. It executes the auto-detection of the port + * by the ownCloud server, if requirements are met. + * + * @constructor + */ + var WizardDetectorTestLoginName = OCA.LDAP.Wizard.WizardDetectorTestAbstract.subClass({ + /** @inheritdoc */ + init: function() { + // given, it is not a configuration key + this.setTargetKey('ldap_test_loginname'); + this.testName = 'TestLoginName'; + this.wizardMethod = 'testLoginName'; + this.runsOnRequest = true; + } + }); + + OCA.LDAP.Wizard.WizardDetectorTestLoginName = WizardDetectorTestLoginName; +})(); diff --git a/apps/user_ldap/js/wizard/wizardDetectorUserCount.js b/apps/user_ldap/js/wizard/wizardDetectorUserCount.js new file mode 100644 index 00000000000..bcff2cf3b10 --- /dev/null +++ b/apps/user_ldap/js/wizard/wizardDetectorUserCount.js @@ -0,0 +1,26 @@ + +/** + * Copyright (c) 2015, Arthur Schiwon <blizzz@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or later. + * See the COPYING-README file. + */ + +OCA = OCA || {}; + +(function() { + + /** + * @classdesc let's the wizard backend count the available users + * + * @constructor + */ + var WizardDetectorUserCount = OCA.LDAP.Wizard.WizardDetectorFilterSimpleRequestAbstract.subClass({ + init: function() { + this.setTargetKey('ldap_user_count'); + this.wizardMethod = 'countUsers'; + this.runsOnRequest = true; + } + }); + + OCA.LDAP.Wizard.WizardDetectorUserCount = WizardDetectorUserCount; +})(); diff --git a/apps/user_ldap/js/wizard/wizardDetectorUserDisplayNameAttribute.js b/apps/user_ldap/js/wizard/wizardDetectorUserDisplayNameAttribute.js new file mode 100644 index 00000000000..ae734480c1c --- /dev/null +++ b/apps/user_ldap/js/wizard/wizardDetectorUserDisplayNameAttribute.js @@ -0,0 +1,39 @@ + +/** + * Copyright (c) 2015, Arthur Schiwon <blizzz@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or later. + * See the COPYING-README file. + */ + +OCA = OCA || {}; + +(function() { + + /** + * @classdesc let's the wizard backend count the available users + * + * @constructor + */ + var WizardDetectorUserDisplayNameAttribute = OCA.LDAP.Wizard.WizardDetectorFilterSimpleRequestAbstract.subClass({ + init: function() { + this.setTargetKey('ldap_user_count'); + this.wizardMethod = 'detectUserDisplayNameAttribute'; + this.runsOnRequest = true; + }, + + /** + * @inheritdoc + */ + run: function(model, configID) { + // default value has capital N. Detected values are always lowercase + if(model.configuration.ldap_display_name && model.configuration.ldap_display_name !== 'displayName') { + // a value is already set. Don't overwrite and don't ask LDAP + // without reason. + return false; + } + this._super(model, configID); + } + }); + + OCA.LDAP.Wizard.WizardDetectorUserDisplayNameAttribute = WizardDetectorUserDisplayNameAttribute; +})(); diff --git a/apps/user_ldap/js/wizard/wizardDetectorUserGroupAssociation.js b/apps/user_ldap/js/wizard/wizardDetectorUserGroupAssociation.js new file mode 100644 index 00000000000..953a0b909a6 --- /dev/null +++ b/apps/user_ldap/js/wizard/wizardDetectorUserGroupAssociation.js @@ -0,0 +1,40 @@ + +/** + * Copyright (c) 2015, Arthur Schiwon <blizzz@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or later. + * See the COPYING-README file. + */ + +OCA = OCA || {}; + +(function() { + + /** + * @classdesc let's the wizard backend count the available users + * + * @constructor + */ + var WizardDetectorUserGroupAssociation = OCA.LDAP.Wizard.WizardDetectorFilterSimpleRequestAbstract.subClass({ + init: function() { + this.setTargetKey('ldap_group_count'); + this.wizardMethod = 'determineGroupMemberAssoc'; + this.runsOnRequest = true; + }, + + /** + * @inheritdoc + */ + run: function(model, configID) { + // TODO: might be better with configuration marker as uniqueMember + // is a valid value (although probably less common then member and memberUid). + if(model.configuration.ldap_group_member_assoc_attribute && model.configuration.ldap_group_member_assoc_attribute !== 'uniqueMember') { + // a value is already set. Don't overwrite and don't ask LDAP + // without reason. + return false; + } + this._super(model, configID); + } + }); + + OCA.LDAP.Wizard.WizardDetectorUserGroupAssociation = WizardDetectorUserGroupAssociation; +})(); diff --git a/apps/user_ldap/js/wizard/wizardDetectorUserObjectClasses.js b/apps/user_ldap/js/wizard/wizardDetectorUserObjectClasses.js new file mode 100644 index 00000000000..0fa324a0809 --- /dev/null +++ b/apps/user_ldap/js/wizard/wizardDetectorUserObjectClasses.js @@ -0,0 +1,29 @@ + +/** + * Copyright (c) 2015, Arthur Schiwon <blizzz@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or later. + * See the COPYING-README file. + */ + +OCA = OCA || {}; + +(function() { + + /** + * @classdesc discovers object classes for the users tab + * + * @constructor + */ + var WizardDetectorUserObjectClasses = OCA.LDAP.Wizard.WizardDetectorFeatureAbstract.subClass({ + /** @inheritdoc */ + init: function() { + // given, it is not a configuration key + this.setTargetKey('ldap_userfilter_objectclass'); + this.wizardMethod = 'determineUserObjectClasses'; + this.featureName = 'UserObjectClasses'; + this.runsOnRequest = true; + } + }); + + OCA.LDAP.Wizard.WizardDetectorUserObjectClasses = WizardDetectorUserObjectClasses; +})(); diff --git a/apps/user_ldap/js/wizard/wizardFilterOnType.js b/apps/user_ldap/js/wizard/wizardFilterOnType.js new file mode 100644 index 00000000000..f3f1368982b --- /dev/null +++ b/apps/user_ldap/js/wizard/wizardFilterOnType.js @@ -0,0 +1,76 @@ +/** + * Copyright (c) 2015, Arthur Schiwon <blizzz@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or later. + * See the COPYING-README file. + */ + +OCA = OCA || {}; + +(function() { + + /** + * @classdesc filters a select box when a text element is typed in + */ + var FilterOnType = OCA.LDAP.Wizard.WizardObject.subClass({ + /** + * initializes a type filter on a text input for a select element + * + * @param {jQuery} $select + * @param {jQuery} $textInput + */ + init: function($select, $textInput) { + this.$select = $select; + this.$textInput = $textInput; + this.updateOptions(); + this.lastSearch = ''; + + var fity = this; + $textInput.bind('change keyup', function () { + if(fity.runID) { + window.clearTimeout(fity.runID); + } + fity.runID = window.setTimeout(function() { + fity.filter(fity); + }, 250); + }); + }, + + /** + * the options will be read in again. Should be called after a + * configuration switch. + */ + updateOptions: function() { + var options = []; + this.$select.find('option').each(function() { + options.push({ + value: $(this).val(), + normalized: $(this).val().toLowerCase() + } + ); + }); + this._options = options; + }, + + /** + * the actual search or filter method + * + * @param {FilterOnType} fity + */ + filter: function(fity) { + var filterVal = fity.$textInput.val().toLowerCase(); + if(filterVal === fity.lastSearch) { + return; + } + fity.lastSearch = filterVal; + fity.$select.empty(); + $.each(fity._options, function() { + if(!filterVal || this.normalized.indexOf(filterVal) > -1) { + fity.$select.append($('<option>').val(this.value).text(this.value)); + } + }); + delete(fity.runID); + } + }); + + OCA.LDAP.Wizard.FilterOnType = FilterOnType; +})();
\ No newline at end of file diff --git a/apps/user_ldap/js/wizard/wizardFilterOnTypeFactory.js b/apps/user_ldap/js/wizard/wizardFilterOnTypeFactory.js new file mode 100644 index 00000000000..eb529212734 --- /dev/null +++ b/apps/user_ldap/js/wizard/wizardFilterOnTypeFactory.js @@ -0,0 +1,27 @@ +/** + * Copyright (c) 2015, Arthur Schiwon <blizzz@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or later. + * See the COPYING-README file. + */ + +OCA = OCA || {}; + +(function() { + + /** + * @classdesc creates instances of OCA.LDAP.Wizard.FilterOnType upon request + */ + var FilterOnTypeFactory = OCA.LDAP.Wizard.WizardObject.subClass({ + /** + * initializes a type filter on a text input for a select element + * + * @param {jQuery} $select + * @param {jQuery} $textInput + */ + get: function($select, $textInput) { + return new OCA.LDAP.Wizard.FilterOnType($select, $textInput); + } + }); + + OCA.LDAP.Wizard.FilterOnTypeFactory = FilterOnTypeFactory; +})();
\ No newline at end of file diff --git a/apps/user_ldap/js/wizard/wizardObject.js b/apps/user_ldap/js/wizard/wizardObject.js new file mode 100644 index 00000000000..a90f1533a26 --- /dev/null +++ b/apps/user_ldap/js/wizard/wizardObject.js @@ -0,0 +1,60 @@ + +/** + * Copyright (c) 2015, Arthur Schiwon <blizzz@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or later. + * See the COPYING-README file. + */ + +OCA = OCA || {}; + +(function() { + var initializing = false; + var superPattern = /xyz/.test(function() { xyz; }) ? /\b_super\b/ : /.*/; + + /** + * @classdesc a base class that allows inheritance + * + * @abstrcact + * @constructor + */ + var WizardObject = function(){}; + WizardObject.subClass = function(properties) { + var _super = this.prototype; + + initializing = true; + var proto = new this(); + initializing = false; + + for (var name in properties) { + proto[name] = + typeof properties[name] === "function" && + typeof _super[name] === 'function' && + superPattern.test(properties[name]) ? + (function (name, fn) { + return function () { + var tmp = this._super; + this._super = _super[name]; + var ret = fn.apply(this, arguments); + this._super = tmp; + return ret; + }; + })(name, properties[name]) : + properties[name]; + }; + + function Class() { + if(!initializing && this.init) { + this.init.apply(this, arguments); + } + } + + Class.prototype = proto; + Class.constructor = Class; + Class.subClass = arguments.callee; + return Class; + }; + + WizardObject.constructor = WizardObject; + + OCA.LDAP.Wizard.WizardObject = WizardObject; +})(); diff --git a/apps/user_ldap/js/wizard/wizardTabAbstractFilter.js b/apps/user_ldap/js/wizard/wizardTabAbstractFilter.js new file mode 100644 index 00000000000..ace8501117f --- /dev/null +++ b/apps/user_ldap/js/wizard/wizardTabAbstractFilter.js @@ -0,0 +1,373 @@ +/** + * Copyright (c) 2015, Arthur Schiwon <blizzz@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or later. + * See the COPYING-README file. + */ + +OCA = OCA || {}; + +(function() { + + /** + * @classdesc This class represents the view belonging to the server tab + * in the LDAP wizard. + */ + var WizardTabAbstractFilter = OCA.LDAP.Wizard.WizardTabGeneric.subClass({ + /** + * @property {number} number that needs to exceeded to use complex group + * selection element + */ + _groupElementSwitchThreshold: 40, + + /** + * @property {boolean} - tells whether multiselect or complex element is + * used for selecting groups + */ + isComplexGroupChooser: false, + + /** @property {string} */ + tabID: '', + + /** + * initializes the instance. Always call it after initialization. + * concrete view must set managed items first, and then call the parent + * init. + * + * @param {OCA.LDAP.Wizard.FilterOnTypeFactory} fotf + * @param {number} [tabIndex] + * @param {string} [tabID] + */ + init: function (fotf, tabIndex, tabID) { + this._super(tabIndex, tabID); + + /** @type {OCA.LDAP.Wizard.FilterOnTypeFactory} */ + this.foTFactory = fotf; + this._initMultiSelect( + this.getGroupsItem().$element, + t('user_ldap', 'Select groups') + ); + this._initMultiSelect( + this.getObjectClassItem().$element, + t('user_ldap', 'Select object classes') + ); + this.filterName = this.getFilterItem().keyName; + this._initFilterModeSwitcher( + this.getToggleItem().$element, + this.getRawFilterContainerItem().$element, + [ this.getObjectClassItem().$element ], + this.getFilterModeKey(), + { + status: 'disabled', + $element: this.getGroupsItem().$element + } + ); + _.bindAll(this, 'onCountButtonClick', 'onSelectGroup', 'onDeselectGroup'); + this.getCountItem().$relatedElements.click(this.onCountButtonClick); + if(this.manyGroupsSupport) { + var $selectBtn = $(this.tabID).find('.ldapGroupListSelect'); + $selectBtn.click(this.onSelectGroup); + var $deselectBtn = $(this.tabID).find('.ldapGroupListDeselect'); + $deselectBtn.click(this.onDeselectGroup); + } + }, + + /** + * returns managed item for the object class chooser. must be + * implemented by concrete view + */ + getObjectClassItem: function () {}, + + /** + * returns managed item for the group chooser. must be + * implemented by concrete view + */ + getGroupsItem: function () {}, + + /** + * returns managed item for the effective filter. must be + * implemented by concrete view + */ + getFilterItem: function () {}, + + /** + * returns managed item for the toggle element. must be + * implemented by concrete view + */ + getToggleItem: function () {}, + + /** + * returns managed item for the raw filter container. must be + * implemented by concrete view + */ + getRawFilterContainerItem: function () {}, + + /** + * returns managed item for the count control. must be + * implemented by concrete view + */ + getCountItem: function () {}, + + /** + * returns name of the filter mode key. must be implemented by concrete + * view + */ + getFilterModeKey: function () {}, + + /** + * Sets the config model for this view and subscribes to some events. + * Also binds the config chooser to the model + * + * @param {OCA.LDAP.Wizard.ConfigModel} configModel + */ + setModel: function(configModel) { + this._super(configModel); + this.configModel.on('configLoaded', this.onConfigSwitch, this); + this.configModel.on('receivedLdapFeature', this.onFeatureReceived, this); + }, + + /** + * @inheritdoc + */ + _setFilterModeAssisted: function () { + this._super(); + if(this.isComplexGroupChooser) { + this.enableElement(this.getGroupsItem().$relatedElements); + } + }, + + /** + * @inheritdoc + */ + _setFilterModeRaw: function () { + this._super(); + if(this.manyGroupsSupport) { + this.disableElement(this.getGroupsItem().$relatedElements); + } + }, + + /** + * sets the selected user object classes + * + * @param {Array} classes + */ + setObjectClass: function(classes) { + this.setElementValue(this.getObjectClassItem().$element, classes); + this.getObjectClassItem().$element.multiselect('refresh'); + }, + + /** + * sets the selected groups + * + * @param {Array} groups + */ + setGroups: function(groups) { + if(!this.isComplexGroupChooser) { + this.setElementValue(this.getGroupsItem().$element, groups); + this.getGroupsItem().$element.multiselect('refresh'); + } else { + var $element = $(this.tabID).find('.ldapGroupListSelected'); + this.equipMultiSelect($element, groups); + } + }, + + /** + * sets the filter + * + * @param {string} filter + */ + setFilter: function(filter) { + this.setElementValue(this.getFilterItem().$element, filter); + this.$filterModeRawContainer.siblings('.ldapReadOnlyFilterContainer').find('.ldapFilterReadOnlyElement').text(filter); + }, + + /** + * sets the user count string + * + * @param {string} countInfo + */ + setCount: function(countInfo) { + this.setElementValue(this.getCountItem().$element, countInfo); + }, + + /** + * @inheritdoc + */ + considerFeatureRequests: function() { + if(!this.isActive) { + return; + } + if(this.getObjectClassItem().$element.find('option').length === 0) { + this.disableElement(this.getObjectClassItem().$element); + this.disableElement(this.getGroupsItem().$element); + if(this.parsedFilterMode === this.configModel.FILTER_MODE_ASSISTED) { + this.configModel.requestWizard(this.getObjectClassItem().keyName); + this.configModel.requestWizard(this.getGroupsItem().keyName); + } + } + }, + + /** + * updates (creates, if necessary) filterOnType instances + * + * @param {string} [only] - if only one search index should be updated + */ + updateFilterOnType: function(only) { + if(_.isUndefined(this.filterOnType)) { + this.filterOnType = []; + + var $availableGroups = $(this.tabID).find('.ldapGroupListAvailable'); + this.filterOnType.push(this.foTFactory.get( + $availableGroups, $(this.tabID).find('.ldapManyGroupsSearch') + )); + var $selectedGroups = $(this.tabID).find('.ldapGroupListSelected'); + this.filterOnType.push(this.foTFactory.get( + $selectedGroups, $(this.tabID).find('.ldapManyGroupsSearch') + )); + } else { + if(_.isUndefined || only.toLowerCase() === 'available') { + this.filterOnType[0].updateOptions(); + } + if(_.isUndefined || only.toLowerCase() === 'selected') { + this.filterOnType[1].updateOptions(); + } + } + }, + + /** + * @inheritdoc + */ + onActivate: function() { + this.considerFeatureRequests(); + }, + + /** + * resets the view when a configuration switch happened. + * + * @param {WizardTabAbstractFilter} view + * @param {Object} configuration + */ + onConfigSwitch: function(view, configuration) { + view.getObjectClassItem().$element.find('option').remove(); + view.getGroupsItem().$element.find('option').remove(); + view.getCountItem().$element.text(''); + $(view.tabID).find('.ldapGroupListAvailable').empty(); + $(view.tabID).find('.ldapGroupListSelected').empty(); + view.updateFilterOnType(); + $(view.tabID).find('.ldapManyGroupsSearch').val(''); + + if(view.isComplexGroupChooser) { + view.isComplexGroupChooser = false; + view.getGroupsItem().$element.multiselect({classes: view.multiSelectPluginClass}); + $(view.tabID).find(".ldapManyGroupsSupport").addClass('hidden'); + } + + view.onConfigLoaded(view, configuration); + }, + + /** + * @inheritdoc + */ + onConfigLoaded: function(view, configuration) { + for(var key in view.managedItems){ + if(!_.isUndefined(configuration[key])) { + var value = configuration[key]; + var methodName = view.managedItems[key].setMethod; + if(!_.isUndefined(view[methodName])) { + view[methodName](value); + // we reimplement it here to update the filter index + // for groups. Maybe we can isolate it? + if(methodName === 'setGroups') { + view.updateFilterOnType('selected'); + } + } + } + } + }, + + /** + * if UserObjectClasses are found, the corresponding element will be + * updated + * + * @param {WizardTabAbstractFilter} view + * @param {FeaturePayload} payload + */ + onFeatureReceived: function(view, payload) { + if(payload.feature === view.getObjectClassItem().featureName) { + view.equipMultiSelect(view.getObjectClassItem().$element, payload.data); + } else if (payload.feature === view.getGroupsItem().featureName) { + if(view.manyGroupsSupport && payload.data.length > view._groupElementSwitchThreshold) { + // we need to fill the left list box, excluding the values + // that are already selected + var $element = $(view.tabID).find('.ldapGroupListAvailable'); + var selected = view.configModel.configuration[view.getGroupsItem().keyName]; + var available = $(payload.data).not(selected).get(); + view.equipMultiSelect($element, available); + view.updateFilterOnType('available'); + $(view.tabID).find(".ldapManyGroupsSupport").removeClass('hidden'); + view.getGroupsItem().$element.multiselect({classes: view.multiSelectPluginClass + ' forceHidden'}); + view.isComplexGroupChooser = true; + } else { + view.isComplexGroupChooser = false; + view.equipMultiSelect(view.getGroupsItem().$element, payload.data); + view.getGroupsItem().$element.multiselect({classes: view.multiSelectPluginClass}); + $(view.tabID).find(".ldapManyGroupsSupport").addClass('hidden'); + + } + } + }, + + /** + * request to count the users with the current filter + * + * @param {Event} event + */ + onCountButtonClick: function(event) { + event.preventDefault(); + // let's clear the field + this.getCountItem().$element.text(''); + this.configModel.requestWizard(this.getCountItem().keyName); + }, + + /** + * saves groups when using the complex UI + * + * @param {Array} groups + * @returns {boolean} + * @private + */ + _saveGroups: function(groups) { + var toSave = ''; + $(groups).each(function() { toSave = toSave + "\n" + this; } ); + this.configModel.set(this.getGroupsItem().keyName, $.trim(toSave)); + }, + + /** + * acts on adding groups to the filter + */ + onSelectGroup: function() { + var $available = $(this.tabID).find('.ldapGroupListAvailable'); + var $selected = $(this.tabID).find('.ldapGroupListSelected'); + var selected = $.map($selected.find('option'), function(e) { return e.value; }); + + this._saveGroups(selected.concat($available.val())); + $available.find('option:selected').prependTo($selected); + this.updateFilterOnType(); + }, + + /** + * acts on removing groups to the filter + */ + onDeselectGroup: function() { + var $available = $(this.tabID).find('.ldapGroupListAvailable'); + var $selected = $(this.tabID).find('.ldapGroupListSelected'); + var selected = $.map($selected.find('option:not(:selected)'), function(e) { return e.value; }); + + this._saveGroups(selected); + $selected.find('option:selected').appendTo($available); + this.updateFilterOnType(); + } + + }); + + OCA.LDAP.Wizard.WizardTabAbstractFilter = WizardTabAbstractFilter; +})();
\ No newline at end of file diff --git a/apps/user_ldap/js/wizard/wizardTabAdvanced.js b/apps/user_ldap/js/wizard/wizardTabAdvanced.js new file mode 100644 index 00000000000..931a547218b --- /dev/null +++ b/apps/user_ldap/js/wizard/wizardTabAdvanced.js @@ -0,0 +1,330 @@ + +/** + * Copyright (c) 2015, Arthur Schiwon <blizzz@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or later. + * See the COPYING-README file. + */ + +OCA = OCA || {}; + +(function() { + + /** + * @classdesc This class represents the view belonging to the advanced tab + * in the LDAP wizard. + */ + var WizardTabAdvanced = OCA.LDAP.Wizard.WizardTabGeneric.subClass({ + /** + * initializes the instance. Always call it after initialization. + * + * @param tabIndex + * @param tabID + */ + init: function (tabIndex, tabID) { + this._super(tabIndex, tabID); + + var items = { + // Connection settings + ldap_configuration_active: { + $element: $('#ldap_configuration_active'), + setMethod: 'setConfigurationState' + }, + ldap_backup_host: { + $element: $('#ldap_backup_host'), + setMethod: 'setBackupHost' + }, + ldap_backup_port: { + $element: $('#ldap_backup_port'), + setMethod: 'setBackupPort' + }, + ldap_override_main_server: { + $element: $('#ldap_override_main_server'), + setMethod: 'setOverrideMainServerState' + }, + ldap_nocase: { + $element: $('#ldap_nocase'), + setMethod: 'setNoCase' + }, + ldap_turn_off_cert_check: { + $element: $('#ldap_turn_off_cert_check'), + setMethod: 'setCertCheckDisabled' + }, + ldap_cache_ttl: { + $element: $('#ldap_cache_ttl'), + setMethod: 'setCacheTTL' + }, + + //Directory Settings + ldap_display_name: { + $element: $('#ldap_display_name'), + setMethod: 'setUserDisplayName' + }, + ldap_base_users: { + $element: $('#ldap_base_users'), + setMethod: 'setBaseDNUsers' + }, + ldap_attributes_for_user_search: { + $element: $('#ldap_attributes_for_user_search'), + setMethod: 'setSearchAttributesUsers' + }, + ldap_group_display_name: { + $element: $('#ldap_group_display_name'), + setMethod: 'setGroupDisplayName' + }, + ldap_base_groups: { + $element: $('#ldap_base_groups'), + setMethod: 'setBaseDNGroups' + }, + ldap_attributes_for_group_search: { + $element: $('#ldap_attributes_for_group_search'), + setMethod: 'setSearchAttributesGroups' + }, + ldap_group_member_assoc_attribute: { + $element: $('#ldap_group_member_assoc_attribute'), + setMethod: 'setGroupMemberAssociationAttribute' + }, + ldap_nested_groups: { + $element: $('#ldap_nested_groups'), + setMethod: 'setUseNestedGroups' + }, + ldap_paging_size: { + $element: $('#ldap_paging_size'), + setMethod: 'setPagingSize' + }, + + //Special Attributes + ldap_quota_attr: { + $element: $('#ldap_quota_attr'), + setMethod: 'setQuotaAttribute' + }, + ldap_quota_def: { + $element: $('#ldap_quota_def'), + setMethod: 'setQuotaDefault' + }, + ldap_email_attr: { + $element: $('#ldap_email_attr'), + setMethod: 'setEmailAttribute' + }, + home_folder_naming_rule: { + $element: $('#home_folder_naming_rule'), + setMethod: 'setHomeFolderAttribute' + } + }; + this.setManagedItems(items); + }, + + /** + * Sets the config model for this view and subscribes to some events. + * Also binds the config chooser to the model + * + * @param {OCA.LDAP.Wizard.ConfigModel} configModel + */ + setModel: function(configModel) { + this._super(configModel); + this.configModel.on('configLoaded', this.onConfigLoaded, this); + this.configModel.on('receivedLdapFeature', this.onResultReceived, this); + }, + + /** + * updates the experienced admin check box + * + * @param {string} isConfigActive contains an int + */ + setConfigurationState: function(isConfigActive) { + this.setElementValue( + this.managedItems.ldap_configuration_active.$element, isConfigActive + ); + }, + + /** + * updates the backup host configuration text field + * + * @param {string} host + */ + setBackupHost: function(host) { + this.setElementValue(this.managedItems.ldap_backup_host.$element, host); + }, + + /** + * updates the backup port configuration text field + * + * @param {string} port + */ + setBackupPort: function(port) { + this.setElementValue(this.managedItems.ldap_backup_port.$element, port); + }, + + /** + * sets whether the main server should be overridden or not + * + * @param {string} doOverride contains an int + */ + setOverrideMainServerState: function(doOverride) { + this.setElementValue( + this.managedItems.ldap_override_main_server.$element, doOverride + ); + }, + + /** + * whether the server is case insensitive. This setting does not play + * a role anymore (probably never had). + * + * @param {string} noCase contains an int + */ + setNoCase: function(noCase) { + this.setElementValue(this.managedItems.ldap_nocase.$element, noCase); + }, + + /** + * sets whether the SSL/TLS certification check shout be disabled + * + * @param {string} doCertCheck contains an int + */ + setCertCheckDisabled: function(doCertCheck) { + this.setElementValue( + this.managedItems.ldap_turn_off_cert_check.$element, doCertCheck + ); + }, + + /** + * sets the time-to-live of the LDAP cache (in seconds) + * + * @param {string} cacheTTL contains an int + */ + setCacheTTL: function(cacheTTL) { + this.setElementValue(this.managedItems.ldap_cache_ttl.$element, cacheTTL); + }, + + /** + * sets the user display name attribute + * + * @param {string} attribute + */ + setUserDisplayName: function(attribute) { + this.setElementValue(this.managedItems.ldap_display_name.$element, attribute); + }, + + /** + * sets the Base DN for users + * + * @param {string} base + */ + setBaseDNUsers: function(base) { + this.setElementValue(this.managedItems.ldap_base_users.$element, base); + }, + + /** + * sets the attributes for user searches + * + * @param {string} attributes + */ + setSearchAttributesUsers: function(attributes) { + this.setElementValue(this.managedItems.ldap_attributes_for_user_search.$element, attributes); + }, + + /** + * sets the display name attribute for groups + * + * @param {string} attribute + */ + setGroupDisplayName: function(attribute) { + this.setElementValue(this.managedItems.ldap_group_display_name.$element, attribute); + }, + + /** + * sets the Base DN for groups + * + * @param {string} base + */ + setBaseDNGroups: function(base) { + this.setElementValue(this.managedItems.ldap_base_groups.$element, base); + }, + + /** + * sets the attributes for group search + * + * @param {string} attributes + */ + setSearchAttributesGroups: function(attributes) { + this.setElementValue(this.managedItems.ldap_attributes_for_group_search.$element, attributes); + }, + + /** + * sets the attribute for the association of users and groups + * + * @param {string} attribute + */ + setGroupMemberAssociationAttribute: function(attribute) { + this.setElementValue(this.managedItems.ldap_group_member_assoc_attribute.$element, attribute); + }, + + /** + * enabled or disables the use of nested groups (groups in groups in + * groups…) + * + * @param {string} useNestedGroups contains an int + */ + setUseNestedGroups: function(useNestedGroups) { + this.setElementValue(this.managedItems.ldap_nested_groups.$element, useNestedGroups); + }, + + /** + * sets the size of pages for paged search + * + * @param {string} size contains an int + */ + setPagingSize: function(size) { + this.setElementValue(this.managedItems.ldap_paging_size.$element, size); + }, + + /** + * sets the email attribute + * + * @param {string} attribute + */ + setEmailAttribute: function(attribute) { + this.setElementValue(this.managedItems.ldap_email_attr.$element, attribute); + }, + + /** + * sets the quota attribute + * + * @param {string} attribute + */ + setQuotaAttribute: function(attribute) { + this.setElementValue(this.managedItems.ldap_quota_attr.$element, attribute); + }, + + /** + * sets the default quota for LDAP users + * + * @param {string} quota contains an int + */ + setQuotaDefault: function(quota) { + this.setElementValue(this.managedItems.ldap_quota_def.$element, quota); + }, + + /** + * sets the attribute for the ownCloud user specific home folder location + * + * @param {string} attribute + */ + setHomeFolderAttribute: function(attribute) { + this.setElementValue(this.managedItems.home_folder_naming_rule.$element, attribute); + }, + + /** + * deals with the result of the Test Connection test + * + * @param {WizardTabAdvanced} view + * @param {FeaturePayload} payload + */ + onResultReceived: function(view, payload) { + if(payload.feature === 'TestConfiguration') { + OC.Notification.showTemporary(payload.data.message); + } + } + }); + + OCA.LDAP.Wizard.WizardTabAdvanced = WizardTabAdvanced; +})();
\ No newline at end of file diff --git a/apps/user_ldap/js/wizard/wizardTabElementary.js b/apps/user_ldap/js/wizard/wizardTabElementary.js new file mode 100644 index 00000000000..9113ecffcf4 --- /dev/null +++ b/apps/user_ldap/js/wizard/wizardTabElementary.js @@ -0,0 +1,346 @@ + +/** + * Copyright (c) 2015, Arthur Schiwon <blizzz@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or later. + * See the COPYING-README file. + */ + +OCA = OCA || {}; + +(function() { + + /** + * @classdesc This class represents the view belonging to the server tab + * in the LDAP wizard. + */ + var WizardTabElementary = OCA.LDAP.Wizard.WizardTabGeneric.subClass({ + /** + * initializes the instance. Always call it after initialization. + * + * @param tabIndex + * @param tabID + */ + init: function (tabIndex, tabID) { + this._super(tabIndex, tabID); + this.isActive = true; + this.configChooserID = '#ldap_serverconfig_chooser'; + + var items = { + ldap_host: { + $element: $('#ldap_host'), + setMethod: 'setHost' + }, + ldap_port: { + $element: $('#ldap_port'), + setMethod: 'setPort', + $relatedElements: $('.ldapDetectPort') + }, + ldap_dn: { + $element: $('#ldap_dn'), + setMethod: 'setAgentDN' + }, + ldap_agent_password: { + $element: $('#ldap_agent_password'), + setMethod: 'setAgentPwd' + }, + ldap_base: { + $element: $('#ldap_base'), + setMethod: 'setBase', + $relatedElements: $('.ldapDetectBase, .ldapTestBase'), + $detectButton: $('.ldapDetectBase'), + $testButton: $('.ldapTestBase') + }, + ldap_base_test: { + $element: $('#ldap_base') + }, + ldap_experienced_admin: { + $element: $('#ldap_experienced_admin'), + setMethod: 'setExperiencedAdmin' + } + }; + this.setManagedItems(items); + _.bindAll(this, 'onPortButtonClick', 'onBaseDNButtonClick', 'onBaseDNTestButtonClick'); + this.managedItems.ldap_port.$relatedElements.click(this.onPortButtonClick); + this.managedItems.ldap_base.$detectButton.click(this.onBaseDNButtonClick); + this.managedItems.ldap_base.$testButton.click(this.onBaseDNTestButtonClick); + }, + + /** + * Sets the config model for this view and subscribes to some events. + * Also binds the config chooser to the model + * + * @param {OCA.LDAP.Wizard.ConfigModel} configModel + */ + setModel: function(configModel) { + this._super(configModel); + this.configModel.on('configLoaded', this.onConfigSwitch, this); + this.configModel.on('newConfiguration', this.onNewConfiguration, this); + this.configModel.on('deleteConfiguration', this.onDeleteConfiguration, this); + this.configModel.on('receivedLdapFeature', this.onTestResultReceived, this); + this._enableConfigChooser(); + this._enableConfigButtons(); + }, + + /** + * returns the currently selected configuration ID + * + * @returns {string} + */ + getConfigID: function() { + return $(this.configChooserID).val(); + }, + + /** + * updates the host configuration text field + * + * @param {string} host + */ + setHost: function(host) { + this.setElementValue(this.managedItems.ldap_host.$element, host); + if(host) { + this.enableElement(this.managedItems.ldap_port.$relatedElements); + } else { + this.disableElement(this.managedItems.ldap_port.$relatedElements); + } + }, + + /** + * updates the port configuration text field + * + * @param {string} port + */ + setPort: function(port) { + this.setElementValue(this.managedItems.ldap_port.$element, port); + }, + + /** + * updates the user (agent) DN text field + * + * @param {string} agentDN + */ + setAgentDN: function(agentDN) { + this.setElementValue(this.managedItems.ldap_dn.$element, agentDN); + }, + + /** + * updates the user (agent) password field + * + * @param {string} agentPwd + */ + setAgentPwd: function(agentPwd) { + this.setElementValue( + this.managedItems.ldap_agent_password.$element, agentPwd + ); + }, + /** + * updates the base DN text area + * + * @param {string} bases + */ + setBase: function(bases) { + this.setElementValue(this.managedItems.ldap_base.$element, bases); + if(!bases) { + this.disableElement(this.managedItems.ldap_base.$testButton); + } else { + this.enableElement(this.managedItems.ldap_base.$testButton); + } + }, + + /** + * updates the experienced admin check box + * + * @param {string} xpAdminMode contains an int + */ + setExperiencedAdmin: function(xpAdminMode) { + this.setElementValue( + this.managedItems.ldap_experienced_admin.$element, xpAdminMode + ); + }, + + /** + * @inheritdoc + */ + overrideErrorMessage: function(message, key) { + switch(key) { + case 'ldap_port': + if (message === 'Invalid credentials') { + return t('user_ldap', 'Please check the credentials, they seem to be wrong.'); + } else { + return t('user_ldap', 'Please specify the port, it could not be auto-detected.'); + } + break; + case 'ldap_base': + if( message === 'Server is unwilling to perform' + || message === 'Could not connect to LDAP' + ) { + return t('user_ldap', 'Base DN could not be auto-detected, please revise credentials, host and port.'); + } + return t('user_ldap', 'Could not detect Base DN, please enter it manually.'); + break; + } + return message; + }, + + /** + * resets the view when a configuration switch happened. + * + * @param {WizardTabElementary} view + * @param {Object} configuration + */ + onConfigSwitch: function(view, configuration) { + view.disableElement(view.managedItems.ldap_port.$relatedElements); + + view.onConfigLoaded(view, configuration); + }, + + /** + * updates the configuration chooser when a new configuration was added + * which also means it is being switched to. The configuration fields + * are updated on a different step. + * + * @param {WizardTabElementary} view + * @param {Object} result + */ + onNewConfiguration: function(view, result) { + if(result.isSuccess === true) { + $(view.configChooserID + ' option:selected').removeAttr('selected'); + var html = '<option value="'+result.configPrefix+'" selected="selected">'+t('user_ldap','{nthServer}. Server', {nthServer: $(view.configChooserID + ' option').length})+'</option>'; + $(view.configChooserID + ' option:last').before(html); + } + }, + + /** + * updates the configuration chooser upon the deletion of a + * configuration and, if necessary, loads an existing one. + * + * @param view + * @param result + */ + onDeleteConfiguration: function(view, result) { + if(result.isSuccess === true) { + if(view.getConfigID() === result.configPrefix) { + // if the deleted value is still the selected one (99% of + // the cases), remove it from the list and load the topmost + $(view.configChooserID + ' option:selected').remove(); + $(view.configChooserID + ' option:first').select(); + if($(view.configChooserID + ' option').length < 2) { + view.configModel.newConfig(false); + } else { + view.configModel.load(view.getConfigID()); + } + } else { + // otherwise just remove the entry + $(view.configChooserID + ' option[value=' + result.configPrefix + ']').remove(); + } + } else { + OC.Notification.showTemporary(result.errorMessage); + } + }, + + /** + * Base DN test results will arrive here + * + * @param {WizardTabElementary} view + * @param {FeaturePayload} payload + */ + onTestResultReceived: function(view, payload) { + if(payload.feature === 'TestBaseDN') { + var message; + if(payload.data.status === 'success') { + var objectsFound = parseInt(payload.data.changes.ldap_test_base, 10); + if(objectsFound < 1) { + message = t('user_ldap', 'No object found in the given Base DN. Please revise.'); + } else if(objectsFound > 1000) { + message = t('user_ldap', 'More then 1.000 directory entries available.'); + } else { + message = t('user_ldap', objectsFound + ' entries available within the provided Base DN'); + } + } else { + message = t('user_ldap', 'An error occurred. Please check the Base DN, as well as connection settings and credentials.'); + if(payload.data.message) { + console.warn(payload.data.message); + } + } + OC.Notification.showTemporary(message); + } + }, + + /** + * request to count the users with the current filter + * + * @param {Event} event + */ + onPortButtonClick: function(event) { + event.preventDefault(); + this.configModel.requestWizard('ldap_port'); + }, + + /** + * request to count the users with the current filter + * + * @param {Event} event + */ + onBaseDNButtonClick: function(event) { + event.preventDefault(); + this.configModel.requestWizard('ldap_base'); + }, + + /** + * request to count the users with the current filter + * + * @param {Event} event + */ + onBaseDNTestButtonClick: function(event) { + event.preventDefault(); + this.configModel.requestWizard('ldap_test_base'); + }, + + /** + * registers the change event on the configuration chooser and makes + * the model load a newly selected configuration + * + * @private + */ + _enableConfigChooser: function() { + var view = this; + $(this.configChooserID).change(function(){ + var value = $(view.configChooserID + ' option:selected:first').attr('value'); + view.configModel.load(value); + }); + }, + + /** + * adds actions to the action buttons for configuration management + * + * @private + */ + _enableConfigButtons: function() { + var view = this; + $('#ldap_action_delete_configuration').click(function(event) { + event.preventDefault(); + OC.dialogs.confirm( + t('user_ldap', 'Do you really want to delete the current Server Configuration?'), + t('user_ldap', 'Confirm Deletion'), + function(doDelete) { + if(doDelete) { + view.configModel.deleteConfig(view.getConfigID()); + } + }, + false + ); + }); + + $('#ldap_action_add_configuration').click(function(event) { + event.preventDefault(); + view.configModel.newConfig(false); + }); + + $('#ldap_action_copy_configuration').click(function(event) { + event.preventDefault(); + view.configModel.newConfig(true); + }); + } + }); + + OCA.LDAP.Wizard.WizardTabElementary = WizardTabElementary; +})();
\ No newline at end of file diff --git a/apps/user_ldap/js/wizard/wizardTabExpert.js b/apps/user_ldap/js/wizard/wizardTabExpert.js new file mode 100644 index 00000000000..6ff93bfd62f --- /dev/null +++ b/apps/user_ldap/js/wizard/wizardTabExpert.js @@ -0,0 +1,130 @@ + +/** + * Copyright (c) 2015, Arthur Schiwon <blizzz@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or later. + * See the COPYING-README file. + */ + +OCA = OCA || {}; + +(function() { + + /** + * @classdesc This class represents the view belonging to the expert tab + * in the LDAP wizard. + */ + var WizardTabExpert = OCA.LDAP.Wizard.WizardTabGeneric.subClass({ + /** + * initializes the instance. Always call it after initialization. + * + * @param tabIndex + * @param tabID + */ + init: function (tabIndex, tabID) { + this._super(tabIndex, tabID); + + var items = { + ldap_expert_username_attr: { + $element: $('#ldap_expert_username_attr'), + setMethod: 'setUsernameAttribute' + }, + ldap_expert_uuid_user_attr: { + $element: $('#ldap_expert_uuid_user_attr'), + setMethod: 'setUserUUIDAttribute' + }, + ldap_expert_uuid_group_attr: { + $element: $('#ldap_expert_uuid_group_attr'), + setMethod: 'setGroupUUIDAttribute' + }, + + //Buttons + ldap_action_clear_user_mappings: { + $element: $('#ldap_action_clear_user_mappings') + }, + ldap_action_clear_group_mappings: { + $element: $('#ldap_action_clear_group_mappings') + } + + }; + this.setManagedItems(items); + _.bindAll(this, 'onClearUserMappingsClick', 'onClearGroupMappingsClick'); + this.managedItems.ldap_action_clear_user_mappings.$element.click(this.onClearUserMappingsClick); + this.managedItems.ldap_action_clear_group_mappings.$element.click(this.onClearGroupMappingsClick); + }, + + /** + * Sets the config model for this view and subscribes to some events. + * Also binds the config chooser to the model + * + * @param {OCA.LDAP.Wizard.ConfigModel} configModel + */ + setModel: function(configModel) { + this._super(configModel); + this.configModel.on('configLoaded', this.onConfigLoaded, this); + this.configModel.on('receivedLdapFeature', this.onResultReceived, this); + }, + + /** + * sets the attribute to be used to create an ownCloud ID (username) + * + * @param {string} attribute + */ + setUsernameAttribute: function(attribute) { + this.setElementValue(this.managedItems.ldap_expert_username_attr.$element, attribute); + }, + + /** + * sets the attribute that provides an unique identifier per LDAP user + * entry + * + * @param {string} attribute + */ + setUserUUIDAttribute: function(attribute) { + this.setElementValue(this.managedItems.ldap_expert_uuid_user_attr.$element, attribute); + }, + + /** + * sets the attribute that provides an unique identifier per LDAP group + * entry + * + * @param {string} attribute + */ + setGroupUUIDAttribute: function(attribute) { + this.setElementValue(this.managedItems.ldap_expert_uuid_group_attr.$element, attribute); + }, + + /** + * requests clearing of all user mappings + */ + onClearUserMappingsClick: function() { + this.configModel.requestWizard('ldap_action_clear_user_mappings', {ldap_clear_mapping: 'user'}); + }, + + /** + * requests clearing of all group mappings + */ + onClearGroupMappingsClick: function() { + this.configModel.requestWizard('ldap_action_clear_group_mappings', {ldap_clear_mapping: 'group'}); + }, + + /** + * deals with the result of the Test Connection test + * + * @param {WizardTabAdvanced} view + * @param {FeaturePayload} payload + */ + onResultReceived: function(view, payload) { + if(payload.feature === 'ClearMappings') { + var message; + if(payload.data.status === 'success') { + message = t('user_ldap', 'Mappings cleared successfully!'); + } else { + message = t('user_ldap', 'Error while clearing the mappings.'); + } + OC.Notification.showTemporary(message); + } + } + }); + + OCA.LDAP.Wizard.WizardTabExpert = WizardTabExpert; +})();
\ No newline at end of file diff --git a/apps/user_ldap/js/wizard/wizardTabGeneric.js b/apps/user_ldap/js/wizard/wizardTabGeneric.js new file mode 100644 index 00000000000..524d2a048a1 --- /dev/null +++ b/apps/user_ldap/js/wizard/wizardTabGeneric.js @@ -0,0 +1,547 @@ + +/** + * Copyright (c) 2015, Arthur Schiwon <blizzz@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or later. + * See the COPYING-README file. + */ + +OCA = OCA || {}; + +(function() { + + /** + * @classdesc An abstract tab view + * @abstract + */ + var WizardTabGeneric = OCA.LDAP.Wizard.WizardObject.subClass({ + isActive: false, + + /** + * @property {string} - class that identifies a multiselect-plugin + * control. + */ + multiSelectPluginClass: 'multiSelectPlugin', + + /** @inheritdoc */ + init: function(tabIndex, tabID) { + this.tabIndex = tabIndex; + this.tabID = tabID; + this.spinner = $('.ldapSpinner').first().clone().removeClass('hidden'); + _.bindAll(this, '_toggleRawFilterMode', '_toggleRawFilterModeConfirmation'); + }, + + /** + * sets the configuration items that are managed by that view. + * + * The parameter contains key-value pairs the key being the + * configuration keys and the value being its setter method. + * + * @param {object} managedItems + */ + setManagedItems: function(managedItems) { + this.managedItems = managedItems; + this._enableAutoSave(); + }, + + /** + * Sets the config model. The concrete view likely wants to subscribe + * to events as well. + * + * @param {OCA.LDAP.Wizard.ConfigModel} configModel + */ + setModel: function(configModel) { + this.configModel = configModel; + this.parsedFilterMode = this.configModel.FILTER_MODE_ASSISTED; + this.configModel.on('detectionStarted', this.onDetectionStarted, this); + this.configModel.on('detectionCompleted', this.onDetectionCompleted, this); + this.configModel.on('serverError', this.onServerError, this); + this.configModel.on('setCompleted', this.onItemSaved, this); + this.configModel.on('configUpdated', this.onConfigLoaded, this); + }, + + /** + * the method can be used to display a different error/information + * message than provided by the ownCloud server response. The concrete + * Tab View may optionally implement it. Returning an empty string will + * avoid any notification. + * + * @param {string} message + * @param {string} key + * @returns {string} + */ + overrideErrorMessage: function(message, key) { + return message; + }, + + /** + * this is called by the main view, if the tab is being switched to. + * The concrete tab view can implement this if necessary. + */ + onActivate: function() { }, + + /** + * updates the tab when the model loaded a configuration and notified + * this view. + * + * @param {WizardTabGeneric} view - this instance + * @param {Object} configuration + */ + onConfigLoaded: function(view, configuration) { + for(var key in view.managedItems){ + if(!_.isUndefined(configuration[key])) { + var value = configuration[key]; + var methodName = view.managedItems[key].setMethod; + if(!_.isUndefined(view[methodName])) { + view[methodName](value); + } + } + } + }, + + /** + * reacts on a set action on the model and updates the tab with the + * valid value. + * + * @param {WizardTabGeneric} view + * @param {Object} result + */ + onItemSaved: function(view, result) { + if(!_.isUndefined(view.managedItems[result.key])) { + var methodName = view.managedItems[result.key].setMethod; + view[methodName](result.value); + if(!result.isSuccess) { + OC.Notification.showTemporary(t('user_ldap', 'Saving failed. Please make sure the database is in Operation. Reload before continuing.')); + console.warn(result.errorMessage); + } + } + }, + + /** + * displays server error messages. + * + * @param view + * @param payload + */ + onServerError: function(view, payload) { + if ( !_.isUndefined(view.managedItems[payload.relatedKey])) { + var message = view.overrideErrorMessage(payload.message, payload.relatedKey); + if(message) { + OC.Notification.showTemporary(message); + } + } + }, + + /** + * disables affected, managed fields if a detector is running against them + * + * @param {WizardTabGeneric} view + * @param {string} key + */ + onDetectionStarted: function(view, key) { + if(!_.isUndefined(view.managedItems[key])) { + view.disableElement(view.managedItems[key].$element); + if(!_.isUndefined(view.managedItems[key].$relatedElements)){ + view.disableElement(view.managedItems[key].$relatedElements); + } + view.attachSpinner(view.managedItems[key].$element.attr('id')); + } + }, + + /** + * enables affected, managed fields after a detector was run against them + * + * @param {WizardTabGeneric} view + * @param {string} key + */ + onDetectionCompleted: function(view, key) { + if(!_.isUndefined(view.managedItems[key])) { + view.enableElement(view.managedItems[key].$element); + if(!_.isUndefined(view.managedItems[key].$relatedElements)){ + view.enableElement(view.managedItems[key].$relatedElements); + } + view.removeSpinner(view.managedItems[key].$element.attr('id')); + } + }, + + /** + * sets the value to an HTML element. Checkboxes, text areas and (text) + * input fields are supported. + * + * @param {jQuery} $element - the target element + * @param {string|number|Array} value + */ + setElementValue: function($element, value) { + // deal with check box + if ($element.is('input[type=checkbox]')) { + this._setCheckBox($element, value); + return; + } + + // deal with text area + if ($element.is('textarea') && $.isArray(value)) { + value = value.join("\n"); + } + + if ($element.is('span')) { + $element.text(value); + } else { + $element.val(value); + } + }, + + /** + * replaces options on a multiselect element + * + * @param {jQuery} $element - the multiselect element + * @param {Array} options + */ + equipMultiSelect: function($element, options) { + $element.empty(); + for (var i in options) { + var name = options[i]; + $element.append($('<option>').val(name).text(name).attr('title', name)); + } + if(!$element.hasClass('ldapGroupList')) { + $element.multiselect('refresh'); + this.enableElement($element); + } + }, + + /** + * enables the specified HTML element + * + * @param {jQuery} $element + */ + enableElement: function($element) { + var isMS = $element.is('select[multiple]'); + var hasOptions = isMS ? ($element.find('option').length > 0) : false; + + if($element.hasClass(this.multiSelectPluginClass) && hasOptions) { + $element.multiselect("enable"); + } else if(!isMS || (isMS && hasOptions)) { + $element.prop('disabled', false); + } + }, + + /** + * disables the specified HTML element + * + * @param {jQuery} $element + */ + disableElement: function($element) { + if($element.hasClass(this.multiSelectPluginClass)) { + $element.multiselect("disable"); + } else { + $element.prop('disabled', 'disabled'); + } + }, + + /** + * attaches a spinner icon to the HTML element specified by ID + * + * @param {string} elementID + */ + attachSpinner: function(elementID) { + if($('#' + elementID + ' + .ldapSpinner').length == 0) { + var spinner = this.spinner.clone(); + var $element = $('#' + elementID); + $(spinner).insertAfter($element); + // and special treatment for multiselects: + if ($element.is('select[multiple]')) { + $('#' + elementID + " + img + button").css('display', 'none'); + } + } + }, + + /** + * removes the spinner icon from the HTML element specified by ID + * + * @param {string} elementID + */ + removeSpinner: function(elementID) { + $('#' + elementID+' + .ldapSpinner').remove(); + // and special treatment for multiselects: + $('#' + elementID + " + button").css('display', 'inline'); + }, + + /** + * whether the wizard works in experienced admin mode + * + * @returns {boolean} + */ + isExperiencedMode: function() { + return parseInt(this.configModel.configuration.ldap_experienced_admin, 10) === 1; + }, + + /** + * sets up auto-save functionality to the managed items + * + * @private + */ + _enableAutoSave: function() { + var view = this; + + for(var id in this.managedItems) { + if(_.isUndefined(this.managedItems[id].$element) + || _.isUndefined(this.managedItems[id].setMethod)) { + continue; + } + var $element = this.managedItems[id].$element; + if (!$element.is('select[multiple]')) { + $element.change(function() { + view._requestSave($(this)); + }); + } + } + }, + + /** + * initializes a multiSelect element + * + * @param {jQuery} $element + * @param {string} caption + * @private + */ + _initMultiSelect: function($element, caption) { + var view = this; + $element.multiselect({ + header: false, + selectedList: 9, + noneSelectedText: caption, + classes: this.multiSelectPluginClass, + close: function() { + view._requestSave($element); + } + }); + }, + + /** + * @typedef {object} viewSaveInfo + * @property {function} val + * @property {function} attr + * @property {function} is + */ + + /** + * requests a save operation from the model for a given value + * represented by a HTML element and its ID. + * + * @param {jQuery|viewSaveInfo} $element + * @private + */ + _requestSave: function($element) { + var value = ''; + if($element.is('input[type=checkbox]') + && !$element.is(':checked')) { + value = 0; + } else if ($element.is('select[multiple]')) { + var entries = $element.multiselect("getChecked"); + for(var i = 0; i < entries.length; i++) { + value = value + "\n" + entries[i].value; + } + value = $.trim(value); + } else { + value = $element.val(); + } + this.configModel.set($element.attr('id'), value); + }, + + /** + * updates a checkbox element according to the provided value + * + * @param {jQuery} $element + * @param {string|number} value + * @private + */ + _setCheckBox: function($element, value) { + if(parseInt(value, 10) === 1) { + $element.attr('checked', 'checked'); + } else { + $element.removeAttr('checked'); + } + }, + + /** + * this is called when the filter mode is switched to assisted. The + * concrete tab view should implement this, to load LDAP features + * (e.g. object classes, groups, attributes…), if necessary. + */ + considerFeatureRequests: function() {}, + + /** + * this is called when the filter mode is switched to Assisted. The + * concrete tab view should request the compilation of the respective + * filter. + */ + requestCompileFilter: function() { + this.configModel.requestWizard(this.filterName); + }, + + /** + * sets the filter mode according to the provided configuration value + * + * @param {string} mode + */ + setFilterMode: function(mode) { + if(parseInt(mode, 10) === this.configModel.FILTER_MODE_ASSISTED) { + this.parsedFilterMode = this.configModel.FILTER_MODE_ASSISTED; + this.considerFeatureRequests(); + this._setFilterModeAssisted(); + if(this.isActive) { + // filter compilation should happen only, if the mode was + // switched manually, but not when initiating the view + this.requestCompileFilter(); + } + } else { + this._setFilterModeRaw(); + this.parsedFilterMode = this.configModel.FILTER_MODE_RAW; + } + }, + + /** + * updates the UI so that it represents the assisted mode setting + * + * @private + */ + _setFilterModeAssisted: function() { + var view = this; + this.$filterModeRawContainer.addClass('invisible'); + var filter = this.$filterModeRawContainer.find('.ldapFilterInputElement').val(); + this.$filterModeRawContainer.siblings('.ldapReadOnlyFilterContainer').find('.ldapFilterReadOnlyElement').text(filter); + this.$filterModeRawContainer.siblings('.ldapReadOnlyFilterContainer').removeClass('hidden'); + $.each(this.filterModeDisableableElements, function(i, $element) { + view.enableElement($element); + }); + if(!_.isUndefined(this.filterModeStateElement)) { + if (this.filterModeStateElement.status === 'enabled') { + this.enableElement(this.filterModeStateElement.$element); + } else { + this.filterModeStateElement.status = 'disabled'; + } + } + }, + + /** + * updates the UI so that it represents the raw mode setting + * + * @private + */ + _setFilterModeRaw: function() { + var view = this; + this.$filterModeRawContainer.removeClass('invisible'); + this.$filterModeRawContainer.siblings('.ldapReadOnlyFilterContainer').addClass('hidden'); + $.each(this.filterModeDisableableElements, function (i, $element) { + view.disableElement($element); + }); + + if(!_.isUndefined(this.filterModeStateElement)) { + if(this.filterModeStateElement.$element.multiselect().attr('disabled') === 'disabled') { + this.filterModeStateElement.status = 'disabled'; + } else { + this.filterModeStateElement.status = 'enabled'; + } + } + if(!_.isUndefined(this.filterModeStateElement)) { + this.disableElement(this.filterModeStateElement.$element); + } + }, + + /** + * @callback toggleConfirmCallback + * @param {boolean} isConfirmed + */ + + /** + * shows a confirmation dialogue before switching from raw to assisted + * mode if experienced mode is enabled. + * + * @param {toggleConfirmCallback} toggleFnc + * @private + */ + _toggleRawFilterModeConfirmation: function(toggleFnc) { + if( !this.isExperiencedMode() + || this.parsedFilterMode === this.configModel.FILTER_MODE_ASSISTED + ) { + toggleFnc(true); + } else { + OCdialogs.confirm( + t('user_ldap', 'Switching the mode will enable automatic LDAP queries. Depending on your LDAP size they may take a while. Do you still want to switch the mode?'), + t('user_ldap', 'Mode switch'), + toggleFnc + ); + } + }, + + /** + * toggles the visibility of a raw filter container and so also the + * state of the multi-select controls. The model is requested to save + * the state. + */ + _toggleRawFilterMode: function() { + var view = this; + this._toggleRawFilterModeConfirmation(function(isConfirmed) { + if(!isConfirmed) { + return; + } + /** var {number} */ + var mode; + if (view.parsedFilterMode === view.configModel.FILTER_MODE_ASSISTED) { + mode = view.configModel.FILTER_MODE_RAW; + } else { + mode = view.configModel.FILTER_MODE_ASSISTED; + } + view.setFilterMode(mode); + /** @var {viewSaveInfo} */ + var saveInfo = { + val: function () { + return mode; + }, + attr: function () { + return view.filterModeKey; + }, + is: function () { + return false; + } + }; + view._requestSave(saveInfo); + }); + }, + + /** + * @typedef {object} filterModeStateElementObj + * @property {string} status - either "enabled" or "disabled" + * @property {jQuery} $element + */ + + /** + * initializes a raw filter mode switcher + * + * @param {jQuery} $switcher - the element receiving the click + * @param {jQuery} $filterModeRawContainer - contains the raw filter + * input elements + * @param {jQuery[]} filterModeDisableableElements - an array of elements + * not belonging to the raw filter part that shall be en/disabled. + * @param {string} filterModeKey - the setting key that save the state + * of the mode + * @param {filterModeStateElementObj} [filterModeStateElement] - one element + * which status (enabled or not) is tracked by a setting + * @private + */ + _initFilterModeSwitcher: function( + $switcher, + $filterModeRawContainer, + filterModeDisableableElements, + filterModeKey, + filterModeStateElement + ) { + this.$filterModeRawContainer = $filterModeRawContainer; + this.filterModeDisableableElements = filterModeDisableableElements; + this.filterModeStateElement = filterModeStateElement; + this.filterModeKey = filterModeKey; + $switcher.click(this._toggleRawFilterMode); + } + + }); + + OCA.LDAP.Wizard.WizardTabGeneric = WizardTabGeneric; +})(); diff --git a/apps/user_ldap/js/wizard/wizardTabGroupFilter.js b/apps/user_ldap/js/wizard/wizardTabGroupFilter.js new file mode 100644 index 00000000000..effb2b3debd --- /dev/null +++ b/apps/user_ldap/js/wizard/wizardTabGroupFilter.js @@ -0,0 +1,124 @@ +/** + * Copyright (c) 2015, Arthur Schiwon <blizzz@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or later. + * See the COPYING-README file. + */ + +OCA = OCA || {}; + +(function() { + + /** + * @classdesc This class represents the view belonging to the server tab + * in the LDAP wizard. + */ + var WizardTabGroupFilter = OCA.LDAP.Wizard.WizardTabAbstractFilter.subClass({ + /** + * @inheritdoc + */ + init: function (fotf, tabIndex, tabID) { + tabID = '#ldapWizard4'; + var items = { + ldap_groupfilter_objectclass: { + $element: $('#ldap_groupfilter_objectclass'), + setMethod: 'setObjectClass', + keyName: 'ldap_groupfilter_objectclass', + featureName: 'GroupObjectClasses' + }, + ldap_group_filter_mode: { + setMethod: 'setFilterMode' + }, + ldap_groupfilter_groups: { + $element: $('#ldap_groupfilter_groups'), + setMethod: 'setGroups', + keyName: 'ldap_groupfilter_groups', + featureName: 'GroupsForGroups', + $relatedElements: $( + tabID + ' .ldapGroupListAvailable,' + + tabID + ' .ldapGroupListSelected,' + + tabID + ' .ldapManyGroupsSearch' + ) + }, + ldap_group_filter: { + $element: $('#ldap_group_filter'), + setMethod: 'setFilter', + keyName: 'ldap_group_filter' + }, + groupFilterRawToggle: { + $element: $('#toggleRawGroupFilter') + }, + groupFilterRawContainer: { + $element: $('#rawGroupFilterContainer') + }, + ldap_group_count: { + $element: $('#ldap_group_count'), + $relatedElements: $('.ldapGetGroupCount'), + setMethod: 'setCount', + keyName: 'ldap_group_count' + } + }; + this.setManagedItems(items); + this.manyGroupsSupport = true; + this._super(fotf, tabIndex, tabID); + }, + + /** + * @inheritdoc + * @returns {Object} + */ + getObjectClassItem: function () { + return this.managedItems.ldap_groupfilter_objectclass; + }, + + /** + * @inheritdoc + * @returns {Object} + */ + getGroupsItem: function () { + return this.managedItems.ldap_groupfilter_groups; + }, + + /** + * @inheritdoc + * @returns {Object} + */ + getFilterItem: function () { + return this.managedItems.ldap_group_filter; + }, + + /** + * @inheritdoc + * @returns {Object} + */ + getToggleItem: function () { + return this.managedItems.groupFilterRawToggle; + }, + + /** + * @inheritdoc + * @returns {Object} + */ + getRawFilterContainerItem: function () { + return this.managedItems.groupFilterRawContainer; + }, + + /** + * @inheritdoc + * @returns {Object} + */ + getCountItem: function () { + return this.managedItems.ldap_group_count; + }, + + /** + * @inheritdoc + * @returns {string} + */ + getFilterModeKey: function () { + return 'ldap_group_filter_mode'; + } + + }); + + OCA.LDAP.Wizard.WizardTabGroupFilter = WizardTabGroupFilter; +})();
\ No newline at end of file diff --git a/apps/user_ldap/js/wizard/wizardTabLoginFilter.js b/apps/user_ldap/js/wizard/wizardTabLoginFilter.js new file mode 100644 index 00000000000..121b43793f2 --- /dev/null +++ b/apps/user_ldap/js/wizard/wizardTabLoginFilter.js @@ -0,0 +1,235 @@ +/** + * Copyright (c) 2015, Arthur Schiwon <blizzz@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or later. + * See the COPYING-README file. + */ + +OCA = OCA || {}; + +(function() { + + /** + * @classdesc This class represents the view belonging to the login filter + * tab in the LDAP wizard. + */ + var WizardTabLoginFilter = OCA.LDAP.Wizard.WizardTabGeneric.subClass({ + /** + * initializes the instance. Always call it after initialization. + * + * @param tabIndex + * @param tabID + */ + init: function (tabIndex, tabID) { + this._super(tabIndex, tabID); + + var items = { + ldap_loginfilter_username: { + $element: $('#ldap_loginfilter_username'), + setMethod: 'setLoginAttributeUsername' + }, + ldap_loginfilter_email: { + $element: $('#ldap_loginfilter_email'), + setMethod: 'setLoginAttributeEmail' + }, + ldap_login_filter_mode: { + setMethod: 'setFilterMode' + }, + ldap_loginfilter_attributes: { + $element: $('#ldap_loginfilter_attributes'), + setMethod: 'setLoginAttributesOther' + }, + ldap_login_filter: { + $element: $('#ldap_login_filter'), + setMethod: 'setLoginFilter' + }, + loginFilterRawToggle: { + $element: $('#toggleRawLoginFilter') + }, + loginFilterRawContainer: { + $element: $('#rawLoginFilterContainer') + }, + ldap_test_loginname: { + $element: $('#ldap_test_loginname'), + $relatedElements: $('.ldapVerifyLoginName') + } + }; + this.setManagedItems(items); + + this.filterModeKey = 'ldapLoginFilterMode'; + this._initMultiSelect( + this.managedItems.ldap_loginfilter_attributes.$element, + t('user_ldap', 'Select attributes') + ); + this.filterName = 'ldap_login_filter'; + this._initFilterModeSwitcher( + this.managedItems.loginFilterRawToggle.$element, + this.managedItems.loginFilterRawContainer.$element, + [ + this.managedItems.ldap_loginfilter_username.$element, + this.managedItems.ldap_loginfilter_email.$element, + this.managedItems.ldap_loginfilter_attributes.$element + ], + 'ldap_login_filter_mode' + ); + _.bindAll(this, 'onVerifyClick'); + this.managedItems.ldap_test_loginname.$relatedElements.click(this.onVerifyClick); + }, + + /** + * Sets the config model for this view and subscribes to some events. + * Also binds the config chooser to the model + * + * @param {OCA.LDAP.Wizard.ConfigModel} configModel + */ + setModel: function(configModel) { + this._super(configModel); + this.configModel.on('configLoaded', this.onConfigSwitch, this); + this.configModel.on('receivedLdapFeature', this.onFeatureReceived, this); + }, + + /** + * sets the selected attributes + * + * @param {Array} attributes + */ + setLoginAttributesOther: function(attributes) { + this.setElementValue(this.managedItems.ldap_loginfilter_attributes.$element, attributes); + this.managedItems.ldap_loginfilter_attributes.$element.multiselect('refresh'); + }, + + /** + * sets the login list filter + * + * @param {string} filter + */ + setLoginFilter: function(filter) { + this.setElementValue(this.managedItems.ldap_login_filter.$element, filter); + this.$filterModeRawContainer.siblings('.ldapReadOnlyFilterContainer').find('.ldapFilterReadOnlyElement').text(filter); + }, + + /** + * updates the username attribute check box + * + * @param {string} useUsername contains an int + */ + setLoginAttributeUsername: function(useUsername) { + this.setElementValue( + this.managedItems.ldap_loginfilter_username.$element, useUsername + ); + }, + + /** + * updates the email attribute check box + * + * @param {string} useEmail contains an int + */ + setLoginAttributeEmail: function(useEmail) { + this.setElementValue( + this.managedItems.ldap_loginfilter_email.$element, useEmail + ); + }, + + /** + * presents the result of the login name test + * + * @param result + */ + handleLoginTestResult: function(result) { + var message; + var isHtml = false; + if(result.status === 'success') { + var usersFound = parseInt(result.changes.ldap_test_loginname, 10); + if(usersFound < 1) { + var filter = result.changes.ldap_test_effective_filter; + message = t('user_ldap', 'User not found. Please check your login attributes and username. Effective filter (to copy-and-paste for command line validation): <br/>' + filter); + console.warn(filter); + isHtml = true; + } else if(usersFound === 1) { + message = t('user_ldap', 'User found and settings verified.'); + } else if(usersFound > 1) { + message = t('user_ldap', 'Settings verified, but one user found. Only the first will be able to login. Consider a more narrow filter.'); + } + } else { + message = t('user_ldap', 'An unspecified error occurred. Please check the settings and the log.'); + if(!_.isUndefined(result.message) && result.message) { + message = result.message; + } + if(message === 'Bad search filter') { + message = t('user_ldap', 'The search filter is invalid, probably due to syntax issues like uneven number of opened and closed brackets. Please revise.'); + } else if(message === 'connection error') { + message = t('user_ldap', 'A connection error to LDAP / AD occurred, please check host, port and credentials.'); + } else if(message === 'missing placeholder') { + message = t('user_ldap', 'The %uid placeholder is missing. It will be replaced with the login name when querying LDAP / AD.'); + } + } + OC.Notification.showTemporary(message, {isHTML: isHtml}); + }, + + /** + * @inheritdoc + */ + considerFeatureRequests: function() { + if(!this.isActive) { + return; + } + if(this.managedItems.ldap_loginfilter_attributes.$element.find('option').length === 0) { + this.disableElement(this.managedItems.ldap_loginfilter_attributes.$element); + if(this.parsedFilterMode === this.configModel.FILTER_MODE_ASSISTED) { + this.configModel.requestWizard('ldap_loginfilter_attributes'); + } + } + }, + + /** + * @inheritdoc + */ + onActivate: function() { + this.considerFeatureRequests(); + }, + + /** + * resets the view when a configuration switch happened. + * + * @param {WizardTabLoginFilter} view + * @param {Object} configuration + */ + onConfigSwitch: function(view, configuration) { + view.managedItems.ldap_loginfilter_attributes.$element.find('option').remove(); + + view.onConfigLoaded(view, configuration); + }, + + /** + * if UserObjectClasses are found, the corresponding element will be + * updated + * + * @param {WizardTabLoginFilter} view + * @param {FeaturePayload} payload + */ + onFeatureReceived: function(view, payload) { + if(payload.feature === 'AvailableAttributes') { + view.equipMultiSelect(view.managedItems.ldap_loginfilter_attributes.$element, payload.data); + } else if(payload.feature === 'TestLoginName') { + view.handleLoginTestResult(payload.data); + } + }, + + /** + * request to test the provided login name + * + * @param {Event} event + */ + onVerifyClick: function(event) { + event.preventDefault(); + var testLogin = this.managedItems.ldap_test_loginname.$element.val(); + if(!testLogin) { + OC.Notification.showTemporary(t('user_ldap', 'Please provide a login name to test against'), 3); + } else { + this.configModel.requestWizard('ldap_test_loginname', {ldap_test_loginname: testLogin}); + } + } + + }); + + OCA.LDAP.Wizard.WizardTabLoginFilter = WizardTabLoginFilter; +})();
\ No newline at end of file diff --git a/apps/user_ldap/js/wizard/wizardTabUserFilter.js b/apps/user_ldap/js/wizard/wizardTabUserFilter.js new file mode 100644 index 00000000000..4ca1199b503 --- /dev/null +++ b/apps/user_ldap/js/wizard/wizardTabUserFilter.js @@ -0,0 +1,136 @@ +/** + * Copyright (c) 2015, Arthur Schiwon <blizzz@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or later. + * See the COPYING-README file. + */ + +OCA = OCA || {}; + +(function() { + + /** + * @classdesc This class represents the view belonging to the server tab + * in the LDAP wizard. + */ + var WizardTabUserFilter = OCA.LDAP.Wizard.WizardTabAbstractFilter.subClass({ + /** + * @inheritdoc + */ + init: function (fotf, tabIndex, tabID) { + tabID = '#ldapWizard2'; + var items = { + ldap_userfilter_objectclass: { + $element: $('#ldap_userfilter_objectclass'), + setMethod: 'setObjectClass', + keyName: 'ldap_userfilter_objectclass', + featureName: 'UserObjectClasses' + }, + ldap_user_filter_mode: { + setMethod: 'setFilterMode' + }, + ldap_userfilter_groups: { + $element: $('#ldap_userfilter_groups'), + setMethod: 'setGroups', + keyName: 'ldap_userfilter_groups', + featureName: 'GroupsForUsers', + $relatedElements: $( + tabID + ' .ldapGroupListAvailable,' + + tabID + ' .ldapGroupListSelected,' + + tabID + ' .ldapManyGroupsSearch' + ) + }, + ldap_userlist_filter: { + $element: $('#ldap_userlist_filter'), + setMethod: 'setFilter', + keyName: 'ldap_userlist_filter' + }, + userFilterRawToggle: { + $element: $('#toggleRawUserFilter') + }, + userFilterRawContainer: { + $element: $('#rawUserFilterContainer') + }, + ldap_user_count: { + $element: $('#ldap_user_count'), + $relatedElements: $('.ldapGetUserCount'), + setMethod: 'setCount', + keyName: 'ldap_user_count' + } + }; + this.setManagedItems(items); + this.manyGroupsSupport = true; + this._super(fotf, tabIndex, tabID); + }, + + /** + * @inheritdoc + * @returns {Object} + */ + getObjectClassItem: function () { + return this.managedItems.ldap_userfilter_objectclass; + }, + + /** + * @inheritdoc + * @returns {Object} + */ + getGroupsItem: function () { + return this.managedItems.ldap_userfilter_groups; + }, + + /** + * @inheritdoc + * @returns {Object} + */ + getFilterItem: function () { + return this.managedItems.ldap_userlist_filter; + }, + + /** + * @inheritdoc + * @returns {Object} + */ + getToggleItem: function () { + return this.managedItems.userFilterRawToggle; + }, + + /** + * @inheritdoc + * @returns {Object} + */ + getRawFilterContainerItem: function () { + return this.managedItems.userFilterRawContainer; + }, + + /** + * @inheritdoc + * @returns {Object} + */ + getCountItem: function () { + return this.managedItems.ldap_user_count; + }, + + /** + * @inheritdoc + * @returns {string} + */ + getFilterModeKey: function () { + return 'ldap_user_filter_mode'; + }, + + /** + * @inheritdoc + */ + overrideErrorMessage: function(message, key) { + if( key === 'ldap_userfilter_groups' + && message === 'memberOf is not supported by the server' + ) { + message = t('user_ldap', 'The group box was disabled, because the LDAP / AD server does not support memberOf.'); + } + return message; + } + + }); + + OCA.LDAP.Wizard.WizardTabUserFilter = WizardTabUserFilter; +})();
\ No newline at end of file diff --git a/apps/user_ldap/lib/access.php b/apps/user_ldap/lib/access.php index e7fb4165c36..f38d11d4be3 100644 --- a/apps/user_ldap/lib/access.php +++ b/apps/user_ldap/lib/access.php @@ -596,6 +596,22 @@ class Access extends LDAPUtility implements user\IUserTools { } /** + * fetches a list of users according to a provided loginName and utilizing + * the login filter. + * + * @param string $loginName + * @param array $attributes optional, list of attributes to read + * @return array + */ + public function fetchUsersByLoginName($loginName, $attributes = array('dn')) { + $loginName = $this->escapeFilterPart($loginName); + $filter = \OCP\Util::mb_str_replace( + '%uid', $loginName, $this->connection->ldapLoginFilter, 'UTF-8'); + $users = $this->fetchListOfUsers($filter, $attributes); + return $users; + } + + /** * @param string $filter * @param string|string[] $attr * @param int $limit @@ -687,6 +703,17 @@ class Access extends LDAPUtility implements user\IUserTools { } /** + * returns the number of available objects on the base DN + * + * @param int|null $limit + * @param int|null $offset + * @return int|bool + */ + public function countObjects($limit = null, $offset = null) { + return $this->count('objectclass=*', $this->connection->ldapBase, array('dn'), $limit, $offset); + } + + /** * retrieved. Results will according to the order in the array. * @param int $limit optional, maximum results to be counted * @param int $offset optional, a starting point diff --git a/apps/user_ldap/lib/configuration.php b/apps/user_ldap/lib/configuration.php index 9b01fd2e559..4621297595d 100644 --- a/apps/user_ldap/lib/configuration.php +++ b/apps/user_ldap/lib/configuration.php @@ -201,11 +201,14 @@ class Configuration { case 'ldapAgentPassword': $readMethod = 'getPwd'; break; - case 'ldapUserDisplayName': case 'ldapGroupDisplayName': $readMethod = 'getLcValue'; break; + case 'ldapUserDisplayName': default: + // user display name does not lower case because + // we rely on an upper case N as indicator whether to + // auto-detect it or not. FIXME $readMethod = 'getValue'; break; } diff --git a/apps/user_ldap/lib/wizard.php b/apps/user_ldap/lib/wizard.php index 97f3002ccaf..cb3dd7f13aa 100644 --- a/apps/user_ldap/lib/wizard.php +++ b/apps/user_ldap/lib/wizard.php @@ -75,9 +75,11 @@ class Wizard extends LDAPUtility { /** * counts entries in the LDAP directory + * * @param string $filter the LDAP search filter * @param string $type a string being either 'users' or 'groups'; - * @return int|bool + * @return bool|int + * @throws \Exception */ public function countEntries($filter, $type) { $reqs = array('ldapHost', 'ldapPort', 'ldapBase'); @@ -88,17 +90,36 @@ class Wizard extends LDAPUtility { throw new \Exception('Requirements not met', 400); } + $attr = array('dn'); // default + $limit = 1001; if($type === 'groups') { - $result = $this->access->countGroups($filter); + $result = $this->access->countGroups($filter, $attr, $limit); } else if($type === 'users') { - $result = $this->access->countUsers($filter); + $result = $this->access->countUsers($filter, $attr, $limit); + } else if ($type === 'objects') { + $result = $this->access->countObjects($limit); } else { - throw new \Exception('internal error: invald object type', 500); + throw new \Exception('internal error: invalid object type', 500); } return $result; } + /** + * formats the return value of a count operation to the string to be + * inserted. + * + * @param bool|int $count + * @return int|string + */ + private function formatCountResult($count) { + $formatted = ($count !== false) ? $count : 0; + if($formatted > 1000) { + $formatted = '> 1000'; + } + return $formatted; + } + public function countGroups() { $filter = $this->configuration->ldapGroupFilter; @@ -109,7 +130,7 @@ class Wizard extends LDAPUtility { } try { - $groupsTotal = $this->countEntries($filter, 'groups'); + $groupsTotal = $this->formatCountResult($this->countEntries($filter, 'groups')); } catch (\Exception $e) { //400 can be ignored, 500 is forwarded if($e->getCode() === 500) { @@ -117,7 +138,6 @@ class Wizard extends LDAPUtility { } return false; } - $groupsTotal = ($groupsTotal !== false) ? $groupsTotal : 0; $output = self::$l->n('%s group found', '%s groups found', $groupsTotal, array($groupsTotal)); $this->result->addChange('ldap_group_count', $output); return $this->result; @@ -130,14 +150,26 @@ class Wizard extends LDAPUtility { public function countUsers() { $filter = $this->access->getFilterForUserCount(); - $usersTotal = $this->countEntries($filter, 'users'); - $usersTotal = ($usersTotal !== false) ? $usersTotal : 0; + $usersTotal = $this->formatCountResult($this->countEntries($filter, 'users')); $output = self::$l->n('%s user found', '%s users found', $usersTotal, array($usersTotal)); $this->result->addChange('ldap_user_count', $output); return $this->result; } /** + * counts any objects in the currently set base dn + * + * @return WizardResult + * @throws \Exception + */ + public function countInBaseDN() { + // we don't need to provide a filter in this case + $total = $this->countEntries(null, 'objects'); + $this->result->addChange('ldap_test_base', $total); + return $this->result; + } + + /** * counts users with a specified attribute * @param string $attr * @param bool $existsCheck @@ -282,45 +314,6 @@ class Wizard extends LDAPUtility { } /** - * return the state of the Group Filter Mode - * @return WizardResult - */ - public function getGroupFilterMode() { - $this->getFilterMode('ldapGroupFilterMode'); - return $this->result; - } - - /** - * return the state of the Login Filter Mode - * @return WizardResult - */ - public function getLoginFilterMode() { - $this->getFilterMode('ldapLoginFilterMode'); - return $this->result; - } - - /** - * return the state of the User Filter Mode - * @return WizardResult - */ - public function getUserFilterMode() { - $this->getFilterMode('ldapUserFilterMode'); - return $this->result; - } - - /** - * return the state of the mode of the specified filter - * @param string $confKey contains the access key of the Configuration - */ - private function getFilterMode($confKey) { - $mode = $this->configuration->$confKey; - if(is_null($mode)) { - $mode = $this->LFILTER_MODE_ASSISTED; - } - $this->result->addChange($confKey, $mode); - } - - /** * detects the available LDAP attributes * @return array|false The instance's WizardResult instance * @throws \Exception @@ -467,8 +460,9 @@ class Wizard extends LDAPUtility { return false; } $this->configuration->setConfiguration(array('ldapGroupMemberAssocAttr' => $attribute)); + $this->result->addChange('ldap_group_member_assoc_attribute', $attribute); //so it will be saved on destruct - $this->result->markChange(); + //$this->result->markChange(); return $this->result; } @@ -604,6 +598,41 @@ class Wizard extends LDAPUtility { } /** + * @return bool|WizardResult + * @param string $loginName + * @throws \Exception + */ + public function testLoginName($loginName) { + if(!$this->checkRequirements(array('ldapHost', + 'ldapPort', + 'ldapBase', + 'ldapLoginFilter', + ))) { + return false; + } + + $cr = $this->access->connection->getConnectionResource(); + if(!$this->ldap->isResource($cr)) { + throw new \Exception('connection error'); + } + + if(mb_strpos($this->access->connection->ldapLoginFilter, '%uid', 0, 'UTF-8') + === false) { + throw new \Exception('missing placeholder'); + } + + $users = $this->access->fetchUsersByLoginName($loginName); + if($this->ldap->errno($cr) !== 0) { + throw new \Exception($this->ldap->error($cr)); + } + $filter = \OCP\Util::mb_str_replace( + '%uid', $loginName, $this->access->connection->ldapLoginFilter, 'UTF-8'); + $this->result->addChange('ldap_test_loginname', count($users)); + $this->result->addChange('ldap_test_effective_filter', $filter); + return $this->result; + } + + /** * Tries to determine the port, requires given Host, User DN and Password * @return WizardResult|false WizardResult on success, false otherwise * @throws \Exception @@ -674,10 +703,13 @@ class Wizard extends LDAPUtility { } $dparts = explode('.', $domain); - $base2 = implode('dc=', $dparts); - if($base !== $base2 && $this->testBaseDN($base2)) { - $this->applyFind('ldap_base', $base2); - return $this->result; + while(count($dparts) > 0) { + $base2 = 'dc=' . implode(',dc=', $dparts); + if ($base !== $base2 && $this->testBaseDN($base2)) { + $this->applyFind('ldap_base', $base2); + return $this->result; + } + array_shift($dparts); } return false; @@ -720,7 +752,7 @@ class Wizard extends LDAPUtility { * @throws \Exception */ private function detectGroupMemberAssoc() { - $possibleAttrs = array('uniqueMember', 'memberUid', 'member', 'unfugasdfasdfdfa'); + $possibleAttrs = array('uniqueMember', 'memberUid', 'member'); $filter = $this->configuration->ldapGroupFilter; if(empty($filter)) { return false; @@ -730,7 +762,7 @@ class Wizard extends LDAPUtility { throw new \Exception('Could not connect to LDAP'); } $base = $this->configuration->ldapBase[0]; - $rr = $this->ldap->search($cr, $base, $filter, $possibleAttrs); + $rr = $this->ldap->search($cr, $base, $filter, $possibleAttrs, 0, 1000); if(!$this->ldap->isResource($rr)) { return false; } @@ -1114,7 +1146,8 @@ class Wizard extends LDAPUtility { //skip when the filter is a wildcard and results were found continue; } - $rr = $this->ldap->search($cr, $base, $filter, array($attr)); + // 20k limit for performance and reason + $rr = $this->ldap->search($cr, $base, $filter, array($attr), 0, 20000); if(!$this->ldap->isResource($rr)) { continue; } diff --git a/apps/user_ldap/settings.php b/apps/user_ldap/settings.php index 85bfbaa076f..f8efa378c7e 100644 --- a/apps/user_ldap/settings.php +++ b/apps/user_ldap/settings.php @@ -29,13 +29,52 @@ OC_Util::checkAdminUser(); -OCP\Util::addScript('user_ldap', 'ldapFilter'); -OCP\Util::addScript('user_ldap', 'experiencedAdmin'); -OCP\Util::addScript('user_ldap', 'settings'); \OC_Util::addVendorScript('user_ldap', 'ui-multiselect/src/jquery.multiselect'); -OCP\Util::addStyle('user_ldap', 'settings'); \OC_Util::addVendorStyle('user_ldap', 'ui-multiselect/jquery.multiselect'); +\OCP\Util::addScript('user_ldap', 'wizard/controller'); +\OCP\Util::addScript('user_ldap', 'wizard/configModel'); +\OCP\Util::addScript('user_ldap', 'wizard/view'); +\OCP\Util::addScript('user_ldap', 'wizard/wizardObject'); +\OCP\Util::addScript('user_ldap', 'wizard/wizardTabGeneric'); +\OCP\Util::addScript('user_ldap', 'wizard/wizardTabElementary'); +\OCP\Util::addScript('user_ldap', 'wizard/wizardTabAbstractFilter'); +\OCP\Util::addScript('user_ldap', 'wizard/wizardTabUserFilter'); +\OCP\Util::addScript('user_ldap', 'wizard/wizardTabLoginFilter'); +\OCP\Util::addScript('user_ldap', 'wizard/wizardTabGroupFilter'); +\OCP\Util::addScript('user_ldap', 'wizard/wizardTabAdvanced'); +\OCP\Util::addScript('user_ldap', 'wizard/wizardTabExpert'); +\OCP\Util::addScript('user_ldap', 'wizard/wizardDetectorQueue'); +\OCP\Util::addScript('user_ldap', 'wizard/wizardDetectorGeneric'); +\OCP\Util::addScript('user_ldap', 'wizard/wizardDetectorPort'); +\OCP\Util::addScript('user_ldap', 'wizard/wizardDetectorBaseDN'); +\OCP\Util::addScript('user_ldap', 'wizard/wizardDetectorFeatureAbstract'); +\OCP\Util::addScript('user_ldap', 'wizard/wizardDetectorUserObjectClasses'); +\OCP\Util::addScript('user_ldap', 'wizard/wizardDetectorGroupObjectClasses'); +\OCP\Util::addScript('user_ldap', 'wizard/wizardDetectorGroupsForUsers'); +\OCP\Util::addScript('user_ldap', 'wizard/wizardDetectorGroupsForGroups'); +\OCP\Util::addScript('user_ldap', 'wizard/wizardDetectorSimpleRequestAbstract'); +\OCP\Util::addScript('user_ldap', 'wizard/wizardDetectorFilterUser'); +\OCP\Util::addScript('user_ldap', 'wizard/wizardDetectorFilterLogin'); +\OCP\Util::addScript('user_ldap', 'wizard/wizardDetectorFilterGroup'); +\OCP\Util::addScript('user_ldap', 'wizard/wizardDetectorUserCount'); +\OCP\Util::addScript('user_ldap', 'wizard/wizardDetectorGroupCount'); +\OCP\Util::addScript('user_ldap', 'wizard/wizardDetectorEmailAttribute'); +\OCP\Util::addScript('user_ldap', 'wizard/wizardDetectorUserDisplayNameAttribute'); +\OCP\Util::addScript('user_ldap', 'wizard/wizardDetectorUserGroupAssociation'); +\OCP\Util::addScript('user_ldap', 'wizard/wizardDetectorAvailableAttributes'); +\OCP\Util::addScript('user_ldap', 'wizard/wizardDetectorTestAbstract'); +\OCP\Util::addScript('user_ldap', 'wizard/wizardDetectorTestLoginName'); +\OCP\Util::addScript('user_ldap', 'wizard/wizardDetectorTestBaseDN'); +\OCP\Util::addScript('user_ldap', 'wizard/wizardDetectorTestConfiguration'); +\OCP\Util::addScript('user_ldap', 'wizard/wizardDetectorClearUserMappings'); +\OCP\Util::addScript('user_ldap', 'wizard/wizardDetectorClearGroupMappings'); +\OCP\Util::addScript('user_ldap', 'wizard/wizardFilterOnType'); +\OCP\Util::addScript('user_ldap', 'wizard/wizardFilterOnTypeFactory'); +\OCP\Util::addScript('user_ldap', 'wizard/wizard'); + +OCP\Util::addStyle('user_ldap', 'settings'); + // fill template $tmpl = new OCP\Template('user_ldap', 'settings'); @@ -55,9 +94,9 @@ $l = \OC::$server->getL10N('user_ldap'); $wizTabs = array(); $wizTabs[] = array('tpl' => 'part.wizard-server', 'cap' => $l->t('Server')); -$wizTabs[] = array('tpl' => 'part.wizard-userfilter', 'cap' => $l->t('User Filter')); -$wizTabs[] = array('tpl' => 'part.wizard-loginfilter', 'cap' => $l->t('Login Filter')); -$wizTabs[] = array('tpl' => 'part.wizard-groupfilter', 'cap' => $l->t('Group Filter')); +$wizTabs[] = array('tpl' => 'part.wizard-userfilter', 'cap' => $l->t('Users')); +$wizTabs[] = array('tpl' => 'part.wizard-loginfilter', 'cap' => $l->t('Login Attributes')); +$wizTabs[] = array('tpl' => 'part.wizard-groupfilter', 'cap' => $l->t('Groups')); $wizTabsCount = count($wizTabs); for($i = 0; $i < $wizTabsCount; $i++) { $tab = new OCP\Template('user_ldap', $wizTabs[$i]['tpl']); @@ -81,4 +120,4 @@ foreach($defaults as $key => $default) { $tmpl->assign($key.'_default', $default); } -return $tmpl->fetchPage(); +return $tmpl->fetchPage();
\ No newline at end of file diff --git a/apps/user_ldap/templates/part.settingcontrols.php b/apps/user_ldap/templates/part.settingcontrols.php index e67cea41d9c..bac00daa39f 100644 --- a/apps/user_ldap/templates/part.settingcontrols.php +++ b/apps/user_ldap/templates/part.settingcontrols.php @@ -1,5 +1,4 @@ <div class="ldapSettingControls"> - <input class="ldap_submit" value="<?php p($l->t('Save'));?>" type="submit"> <button type="button" class="ldap_action_test_connection" name="ldap_action_test_connection"> <?php p($l->t('Test Configuration'));?> </button> diff --git a/apps/user_ldap/templates/part.wizard-groupfilter.php b/apps/user_ldap/templates/part.wizard-groupfilter.php index 1953d2eaa6e..bfcfd115218 100644 --- a/apps/user_ldap/templates/part.wizard-groupfilter.php +++ b/apps/user_ldap/templates/part.wizard-groupfilter.php @@ -5,31 +5,48 @@ </p> <p> <label for="ldap_groupfilter_objectclass"> - <?php p($l->t('only those object classes:'));?> + <?php p($l->t('Only these object classes:'));?> </label> <select id="ldap_groupfilter_objectclass" multiple="multiple" - name="ldap_groupfilter_objectclass"> + name="ldap_groupfilter_objectclass" class="multiSelectPlugin"> </select> </p> <p> <label for="ldap_groupfilter_groups"> - <?php p($l->t('only from those groups:'));?> + <?php p($l->t('Only from these groups:'));?> </label> + <input type="text" class="ldapManyGroupsSupport ldapManyGroupsSearch hidden" placeholder="<?php p($l->t('Search groups'));?>" /> + <select id="ldap_groupfilter_groups" multiple="multiple" - name="ldap_groupfilter_groups"> + name="ldap_groupfilter_groups" class="multiSelectPlugin"> </select> + + </p> + <p class="ldapManyGroupsSupport hidden"> + <label></label> + <select class="ldapGroupList ldapGroupListAvailable" multiple="multiple" + title="<?php p($l->t('Available groups'));?>"></select> + <span> + <button class="ldapGroupListSelect" type="button">></button><br/> + <button class="ldapGroupListDeselect" type="button"><</button> + </span> + <select class="ldapGroupList ldapGroupListSelected" multiple="multiple" + title="<?php p($l->t('Selected groups'));?>"></select> </p> <p> - <label><a id='toggleRawGroupFilter'>↓ <?php p($l->t('Edit raw filter instead'));?></a></label> + <label><a id='toggleRawGroupFilter' class='ldapToggle'>↓ <?php p($l->t('Edit LDAP Query'));?></a></label> + </p> + <p id="ldapReadOnlyGroupFilterContainer" class="hidden ldapReadOnlyFilterContainer"> + <label><?php p($l->t('LDAP Filter:'));?></label> + <span class="ldapFilterReadOnlyElement ldapInputColElement"></span> </p> <p id="rawGroupFilterContainer" class="invisible"> - <input type="text" id="ldap_group_filter" name="ldap_group_filter" - class="lwautosave" - placeholder="<?php p($l->t('Raw LDAP filter'));?>" - title="<?php p($l->t('The filter specifies which LDAP groups shall have access to the %s instance.', $theme->getName()));?>" - /> + <textarea type="text" id="ldap_group_filter" name="ldap_group_filter" + placeholder="<?php p($l->t('Edit LDAP Query'));?>" + title="<?php p($l->t('The filter specifies which LDAP groups shall have access to the %s instance.', $theme->getName()));?>"> + </textarea> <button class="ldapGetEntryCount hidden" name="ldapGetEntryCount" type="button"> <?php p($l->t('Test Filter'));?> </button> @@ -38,7 +55,10 @@ <div class="ldapWizardInfo invisible"> </div> </p> <p class="ldap_count"> - <span id="ldap_group_count">0 <?php p($l->t('groups found'));?></span> + <button class="ldapGetEntryCount ldapGetGroupCount" name="ldapGetEntryCount" type="button"> + <?php p($l->t('Verify settings and count groups'));?> + </button> + <span id="ldap_group_count"></span> </p> <?php print_unescaped($_['wizardControls']); ?> </div> diff --git a/apps/user_ldap/templates/part.wizard-loginfilter.php b/apps/user_ldap/templates/part.wizard-loginfilter.php index 3dde46fa979..fa17a9b430b 100644 --- a/apps/user_ldap/templates/part.wizard-loginfilter.php +++ b/apps/user_ldap/templates/part.wizard-loginfilter.php @@ -1,23 +1,25 @@ <fieldset id="ldapWizard3"> <div> <p> - <?php p($l->t('Users login with this attribute:'));?> + <?php p($l->t('When logging in, %s will find the user based on the following attributes:', $theme->getName()));?> </p> <p> <label for="ldap_loginfilter_username"> - <?php p($l->t('LDAP Username:'));?> + <?php p($l->t('LDAP / AD Username:'));?> </label> <input type="checkbox" id="ldap_loginfilter_username" - name="ldap_loginfilter_username" value="1" class="lwautosave" /> + title="<?php p($l->t('Allows login against the LDAP / AD username, which is either uid or samaccountname and will be detected.'));?>" + name="ldap_loginfilter_username" value="1" /> </p> <p> <label for="ldap_loginfilter_email"> - <?php p($l->t('LDAP Email Address:'));?> + <?php p($l->t('LDAP / AD Email Address:'));?> </label> <input type="checkbox" id="ldap_loginfilter_email" - name="ldap_loginfilter_email" value="1" class="lwautosave" /> + title="<?php p($l->t('Allows login against an email attribute. Mail and mailPrimaryAddress will be allowed.'));?>" + name="ldap_loginfilter_email" value="1" /> </p> <p> <label for="ldap_loginfilter_attributes"> @@ -25,23 +27,35 @@ </label> <select id="ldap_loginfilter_attributes" multiple="multiple" - name="ldap_loginfilter_attributes"> + name="ldap_loginfilter_attributes" class="multiSelectPlugin"> </select> </p> <p> - <label><a id='toggleRawLoginFilter'>↓ <?php p($l->t('Edit raw filter instead'));?></a></label> + <label><a id='toggleRawLoginFilter' class='ldapToggle'>↓ <?php p($l->t('Edit LDAP Query'));?></a></label> + </p> + <p id="ldapReadOnlyLoginFilterContainer" class="hidden ldapReadOnlyFilterContainer"> + <label><?php p($l->t('LDAP Filter:'));?></label> + <span class="ldapFilterReadOnlyElement ldapInputColElement"></span> </p> <p id="rawLoginFilterContainer" class="invisible"> - <input type="text" id="ldap_login_filter" name="ldap_login_filter" - class="lwautosave" - placeholder="<?php p($l->t('Raw LDAP filter'));?>" - title="<?php p($l->t('Defines the filter to apply, when login is attempted. %%uid replaces the username in the login action. Example: "uid=%%uid"'));?>" - /> + <textarea type="text" id="ldap_login_filter" name="ldap_login_filter" + class="ldapFilterInputElement" + placeholder="<?php p($l->t('Edit LDAP Query'));?>" + title="<?php p($l->t('Defines the filter to apply, when login is attempted. %%uid replaces the username in the login action. Example: "uid=%%uid"'));?>"> + </textarea> </p> <p> <div class="ldapWizardInfo invisible"> </div> </p> - + <p class="ldap_verify"> + <input type="text" id="ldap_test_loginname" name="ldap_test_loginname" + placeholder="<?php p($l->t('Test Loginname'));?>" + class="ldapVerifyInput" + title="Attempts to receive a DN for the given loginname and the current login filter"/> + <button class="ldapVerifyLoginName" name="ldapTestLoginSettings" type="button"> + <?php p($l->t('Verify settings'));?> + </button> + </p> <?php print_unescaped($_['wizardControls']); ?> </div> </fieldset>
\ No newline at end of file diff --git a/apps/user_ldap/templates/part.wizard-server.php b/apps/user_ldap/templates/part.wizard-server.php index c1744143f98..3ce912fac4a 100644 --- a/apps/user_ldap/templates/part.wizard-server.php +++ b/apps/user_ldap/templates/part.wizard-server.php @@ -22,32 +22,41 @@ } } ?> - <option value="NEW"><?php p($l->t('Add Server Configuration'));?></option> </select> + <button type="button" id="ldap_action_add_configuration" + name="ldap_action_add_configuration" class="icon-add" + title="Adds a new and blank configuration"> </button> + <button type="button" id="ldap_action_copy_configuration" + name="ldap_action_copy_configuration" + class="ldapIconCopy icon-default-style" + title="Copy current configuration into new directory binding"> </button> <button type="button" id="ldap_action_delete_configuration" - name="ldap_action_delete_configuration"><?php p($l->t('Delete Configuration'));?></button> + name="ldap_action_delete_configuration" class="icon-delete" + title="Delete the current configuration"> </button> </p> <div class="hostPortCombinator"> <div class="tablerow"> <div class="tablecell"> <div class="table"> - <input type="text" class="host tablecell lwautosave" id="ldap_host" + <input type="text" class="host" id="ldap_host" name="ldap_host" placeholder="<?php p($l->t('Host'));?>" title="<?php p($l->t('You can omit the protocol, except you require SSL. Then start with ldaps://'));?>" /> <span> <input type="number" id="ldap_port" name="ldap_port" - class="lwautosave" placeholder="<?php p($l->t('Port'));?>" /> + <button class="ldapDetectPort" name="ldapDetectPort" type="button"> + <?php p($l->t('Detect Port'));?> + </button> </span> </div> </div> </div> <div class="tablerow"> <input type="text" id="ldap_dn" name="ldap_dn" - class="tablecell lwautosave" + class="tablecell" placeholder="<?php p($l->t('User DN'));?>" autocomplete="off" title="<?php p($l->t('The DN of the client user with which the bind shall be done, e.g. uid=agent,dc=example,dc=com. For anonymous access, leave DN and Password empty.'));?>" /> @@ -55,7 +64,7 @@ <div class="tablerow"> <input type="password" id="ldap_agent_password" - class="tablecell lwautosave" name="ldap_agent_password" + class="tablecell" name="ldap_agent_password" placeholder="<?php p($l->t('Password'));?>" autocomplete="off" title="<?php p($l->t('For anonymous access, leave DN and Password empty.'));?>" /> @@ -63,15 +72,21 @@ <div class="tablerow"> <textarea id="ldap_base" name="ldap_base" - class="tablecell lwautosave" + class="tablecell" placeholder="<?php p($l->t('One Base DN per line'));?>" title="<?php p($l->t('You can specify Base DN for users and groups in the Advanced tab'));?>"> </textarea> + <button class="ldapDetectBase" name="ldapDetectBase" type="button"> + <?php p($l->t('Detect Base DN'));?> + </button> + <button class="ldapTestBase" name="ldapTestBase" type="button"> + <?php p($l->t('Test Base DN'));?> + </button> </div> <div class="tablerow left"> <input type="checkbox" id="ldap_experienced_admin" value="1" - name="ldap_experienced_admin" class="tablecell lwautosave" + name="ldap_experienced_admin" class="tablecell" title="<?php p($l->t('Avoids automatic LDAP requests. Better for bigger setups, but requires some LDAP knowledge.'));?>" /> <label for="ldap_experienced_admin" class="tablecell"> diff --git a/apps/user_ldap/templates/part.wizard-userfilter.php b/apps/user_ldap/templates/part.wizard-userfilter.php index 99a6e75370b..691c41a66a6 100644 --- a/apps/user_ldap/templates/part.wizard-userfilter.php +++ b/apps/user_ldap/templates/part.wizard-userfilter.php @@ -5,40 +5,61 @@ </p> <p> <label for="ldap_userfilter_objectclass"> - <?php p($l->t('only those object classes:'));?> + <?php p($l->t('Only these object classes:'));?> </label> <select id="ldap_userfilter_objectclass" multiple="multiple" - name="ldap_userfilter_objectclass"> + name="ldap_userfilter_objectclass" class="multiSelectPlugin"> </select> </p> <p> + <label></label> + <span class="ldapInputColElement"><?php p($l->t('The most common object classes for users are organizationalPerson, person, user, and inetOrgPerson. If you are not sure which object class to select, please consult your directory admin.'));?></span> + </p> + <p> <label for="ldap_userfilter_groups"> - <?php p($l->t('only from those groups:'));?> + <?php p($l->t('Only from these groups:'));?> </label> + <input type="text" class="ldapManyGroupsSupport ldapManyGroupsSearch hidden" placeholder="<?php p($l->t('Search groups'));?>" /> + <select id="ldap_userfilter_groups" multiple="multiple" - name="ldap_userfilter_groups"> + name="ldap_userfilter_groups" class="multiSelectPlugin"> </select> </p> + <p class="ldapManyGroupsSupport hidden"> + <label></label> + <select class="ldapGroupList ldapGroupListAvailable" multiple="multiple" + title="<?php p($l->t('Available groups'));?>"></select> + <span> + <button class="ldapGroupListSelect" type="button">></button><br/> + <button class="ldapGroupListDeselect" type="button"><</button> + </span> + <select class="ldapGroupList ldapGroupListSelected" multiple="multiple" + title="<?php p($l->t('Selected groups'));?>"></select> + </p> <p> - <label><a id='toggleRawUserFilter'>↓ <?php p($l->t('Edit raw filter instead'));?></a></label> - </p> - <p id="rawUserFilterContainer" class="invisible"> - <input type="text" id="ldap_userlist_filter" name="ldap_userlist_filter" - class="lwautosave" - placeholder="<?php p($l->t('Raw LDAP filter'));?>" - title="<?php p($l->t('The filter specifies which LDAP users shall have access to the %s instance.', $theme->getName()));?>" - /> - <button class="ldapGetEntryCount hidden" name="ldapGetEntryCount" type="button"> - <?php p($l->t('Test Filter'));?> - </button> + <label><a id='toggleRawUserFilter' class='ldapToggle'>↓ <?php p($l->t('Edit LDAP Query'));?></a></label> + </p> + <p id="ldapReadOnlyUserFilterContainer" class="hidden ldapReadOnlyFilterContainer"> + <label><?php p($l->t('LDAP Filter:'));?></label> + <span class="ldapFilterReadOnlyElement ldapInputColElement"></span> + </p> + <p id="rawUserFilterContainer"> + <textarea type="text" id="ldap_userlist_filter" name="ldap_userlist_filter" + class="ldapFilterInputElement" + placeholder="<?php p($l->t('Edit LDAP Query'));?>" + title="<?php p($l->t('The filter specifies which LDAP users shall have access to the %s instance.', $theme->getName()));?>"> + </textarea> </p> <p> <div class="ldapWizardInfo invisible"> </div> </p> <p class="ldap_count"> - <span id="ldap_user_count">0 <?php p($l->t('users found'));?></span> + <button class="ldapGetEntryCount ldapGetUserCount" name="ldapGetEntryCount" type="button"> + <?php p($l->t('Verify settings and count users'));?> + </button> + <span id="ldap_user_count"></span> </p> <?php print_unescaped($_['wizardControls']); ?> </div> diff --git a/apps/user_ldap/templates/settings.php b/apps/user_ldap/templates/settings.php index 6aa2183726b..833bef8c24d 100644 --- a/apps/user_ldap/templates/settings.php +++ b/apps/user_ldap/templates/settings.php @@ -65,5 +65,6 @@ <?php print_unescaped($_['settingControls']); ?> </fieldset> </div> - + <!-- Spinner Template --> + <img class="ldapSpinner hidden" src="<?php p(\OCP\Util::imagePath('core', 'loading.gif')); ?>"> </form> diff --git a/apps/user_ldap/templates/wizard-container.php b/apps/user_ldap/templates/wizard-container.php new file mode 100644 index 00000000000..fbfa8899de6 --- /dev/null +++ b/apps/user_ldap/templates/wizard-container.php @@ -0,0 +1,3 @@ +<form id="ldapWizard" class="section" action="#" method="post"> + <h2><?php p($l->t('LDAP2')); ?></h2> +</form>
\ No newline at end of file diff --git a/apps/user_ldap/user_ldap.php b/apps/user_ldap/user_ldap.php index ea1371c14d3..54e14c093f3 100644 --- a/apps/user_ldap/user_ldap.php +++ b/apps/user_ldap/user_ldap.php @@ -79,14 +79,10 @@ class USER_LDAP extends BackendUtility implements \OCP\IUserBackend, \OCP\UserIn * Check if the password is correct without logging in the user */ public function checkPassword($uid, $password) { - $uid = $this->access->escapeFilterPart($uid); - //find out dn of the user name $attrs = array($this->access->connection->ldapUserDisplayName, 'dn', 'uid', 'samaccountname'); - $filter = \OCP\Util::mb_str_replace( - '%uid', $uid, $this->access->connection->ldapLoginFilter, 'UTF-8'); - $users = $this->access->fetchListOfUsers($filter, $attrs); + $users = $this->access->fetchUsersByLoginName($uid, $attrs); if(count($users) < 1) { return false; } |