summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--apps/user_ldap/appinfo/update.php4
-rw-r--r--apps/user_ldap/appinfo/version2
-rw-r--r--apps/user_ldap/css/settings.css25
-rw-r--r--apps/user_ldap/js/experiencedAdmin.js100
-rw-r--r--apps/user_ldap/js/ldapFilter.js73
-rw-r--r--apps/user_ldap/js/settings.js348
-rw-r--r--apps/user_ldap/lib/configuration.php179
-rw-r--r--apps/user_ldap/settings.php1
-rw-r--r--apps/user_ldap/templates/part.wizard-groupfilter.php7
-rw-r--r--apps/user_ldap/templates/part.wizard-server.php10
-rw-r--r--apps/user_ldap/templates/part.wizard-userfilter.php7
-rw-r--r--apps/user_ldap/templates/part.wizardcontrols.php1
-rw-r--r--lib/private/server.php7
-rw-r--r--lib/private/share/share.php53
-rw-r--r--lib/private/tagging/tag.php89
-rw-r--r--lib/private/tagging/tagmapper.php77
-rw-r--r--lib/private/tagmanager.php24
-rw-r--r--lib/private/tags.php345
-rw-r--r--lib/public/itagmanager.php5
-rw-r--r--lib/public/itags.php27
-rw-r--r--tests/lib/share/backend.php3
-rw-r--r--tests/lib/tags.php64
22 files changed, 1106 insertions, 345 deletions
diff --git a/apps/user_ldap/appinfo/update.php b/apps/user_ldap/appinfo/update.php
index 1e706ce869b..5fad23de4f6 100644
--- a/apps/user_ldap/appinfo/update.php
+++ b/apps/user_ldap/appinfo/update.php
@@ -19,7 +19,7 @@ foreach($configPrefixes as $config) {
'user_ldap', $config.'ldap_uuid_user_attribute', 'not existing');
if($state === 'non existing') {
$value = \OCP\Config::getAppValue(
- 'user_ldap', $config.'ldap_uuid_attribute', 'auto');
+ 'user_ldap', $config.'ldap_uuid_attribute', '');
\OCP\Config::setAppValue(
'user_ldap', $config.'ldap_uuid_user_attribute', $value);
\OCP\Config::setAppValue(
@@ -30,7 +30,7 @@ foreach($configPrefixes as $config) {
'user_ldap', $config.'ldap_expert_uuid_user_attr', 'not existing');
if($state === 'non existing') {
$value = \OCP\Config::getAppValue(
- 'user_ldap', $config.'ldap_expert_uuid_attr', 'auto');
+ 'user_ldap', $config.'ldap_expert_uuid_attr', '');
\OCP\Config::setAppValue(
'user_ldap', $config.'ldap_expert_uuid_user_attr', $value);
\OCP\Config::setAppValue(
diff --git a/apps/user_ldap/appinfo/version b/apps/user_ldap/appinfo/version
index 17b2ccd9bf9..6f2743d65dc 100644
--- a/apps/user_ldap/appinfo/version
+++ b/apps/user_ldap/appinfo/version
@@ -1 +1 @@
-0.4.3
+0.4.4
diff --git a/apps/user_ldap/css/settings.css b/apps/user_ldap/css/settings.css
index 3051cc8058e..8f339451c64 100644
--- a/apps/user_ldap/css/settings.css
+++ b/apps/user_ldap/css/settings.css
@@ -6,6 +6,7 @@
.tablerow {
display: table-row;
white-space: nowrap;
+ text-align: left;
}
.tablerow input, .tablerow textarea {
@@ -16,6 +17,10 @@
height: 15px;
}
+#ldap .tablerow label {
+ margin-left: 3px;
+}
+
.invisible {
visibility: hidden;
}
@@ -77,6 +82,10 @@
margin: 5px;
}
+.ldap_count {
+ line-height: 45px;
+}
+
.ldapSettingControls {
margin-top: 3px;
}
@@ -103,6 +112,10 @@
vertical-align: bottom;
}
+#ldap input[type=checkbox] {
+ width: 15px !important;
+}
+
select[multiple=multiple] + button {
height: 28px;
padding-top: 6px !important;
@@ -110,6 +123,18 @@ select[multiple=multiple] + button {
max-width: 40%;
}
+.save-cursor {
+ cursor: wait;
+}
+
+#ldap .ldap_saving {
+ margin-right: 15px;
+ color: orange;
+ font-weight: bold;
+}
+
+#ldap .ldap_saving img { height: 15px; }
+
.ldap_config_state_indicator_sign {
display: inline-block;
height: 16px;
diff --git a/apps/user_ldap/js/experiencedAdmin.js b/apps/user_ldap/js/experiencedAdmin.js
new file mode 100644
index 00000000000..fac8dd6470f
--- /dev/null
+++ b/apps/user_ldap/js/experiencedAdmin.js
@@ -0,0 +1,100 @@
+/**
+ * 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} 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() {
+ var containers = {
+ 'toggleRawGroupFilter': '#rawGroupFilterContainer',
+ 'toggleRawLoginFilter': '#rawLoginFilterContainer',
+ 'toggleRawUserFilter' : '#rawUserFilterContainer'
+ };
+
+ for(var method in containers) {
+ if($(containers[method]).hasClass('invisible')) {
+ this.wizard[method]();
+ }
+ }
+};
+
+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
index e9f60e7ba3c..bb66c1df2ee 100644
--- a/apps/user_ldap/js/ldapFilter.js
+++ b/apps/user_ldap/js/ldapFilter.js
@@ -1,19 +1,30 @@
/* global LdapWizard */
-function LdapFilter(target) {
+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;
if( target === 'User' ||
target === 'Login' ||
target === 'Group') {
this.target = target;
- this.determineMode();
}
}
+LdapFilter.prototype.activate = function() {
+ if(this.activated) {
+ return;
+ }
+ this.activated = true;
+
+ this.determineMode();
+};
+
LdapFilter.prototype.compose = function(callback) {
var action;
@@ -22,6 +33,11 @@ LdapFilter.prototype.compose = function(callback) {
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') {
@@ -30,11 +46,6 @@ LdapFilter.prototype.compose = function(callback) {
action = 'getGroupFilter';
}
- if(!$('#raw'+this.target+'FilterContainer').hasClass('invisible')) {
- //Raw filter editing, i.e. user defined filter, don't compose
- return;
- }
-
var param = 'action='+action+
'&ldap_serverconfig_chooser='+
encodeURIComponent($('#ldap_serverconfig_chooser').val());
@@ -44,10 +55,8 @@ LdapFilter.prototype.compose = function(callback) {
LdapWizard.ajax(param,
function(result) {
LdapWizard.applyChanges(result);
- if(filter.target === 'User') {
- LdapWizard.countUsers();
- } else if(filter.target === 'Group') {
- LdapWizard.countGroups();
+ filter.updateCount();
+ if(filter.target === 'Group') {
LdapWizard.detectGroupMemberAssoc();
}
if(typeof callback !== 'undefined') {
@@ -82,6 +91,7 @@ LdapFilter.prototype.determineMode = function() {
filter.mode + '« of type ' + typeof filter.mode);
}
filter.unlock();
+ filter.determineModeCallback(filter.mode);
},
function () {
//on error case get back to default i.e. Assisted
@@ -90,10 +100,21 @@ LdapFilter.prototype.determineMode = function() {
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) {
@@ -101,3 +122,33 @@ LdapFilter.prototype.unlock = function() {
this.compose();
}
};
+
+LdapFilter.prototype.findFeatures = function() {
+ //TODO: reset this.foundFeatures when any base DN changes
+ 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");
+ }
+};
+
+LdapFilter.prototype.updateCount = function(doneCallback) {
+ if(this.target === 'User') {
+ LdapWizard.countUsers(doneCallback);
+ } else if (this.target === 'Group') {
+ LdapWizard.countGroups(doneCallback);
+ }
+};
diff --git a/apps/user_ldap/js/settings.js b/apps/user_ldap/js/settings.js
index fd84ca1980b..1627528200f 100644
--- a/apps/user_ldap/js/settings.js
+++ b/apps/user_ldap/js/settings.js
@@ -122,7 +122,7 @@ var LdapConfiguration = {
OC.filePath('user_ldap','ajax','clearMappings.php'),
'ldap_clear_mapping='+encodeURIComponent(mappingSubject),
function(result) {
- if(result.status == 'success') {
+ if(result.status === 'success') {
OC.dialogs.info(
t('user_ldap', 'mappings cleared'),
t('user_ldap', 'Success')
@@ -148,23 +148,32 @@ var LdapWizard = {
userFilter: false,
loginFilter: false,
groupFilter: false,
+ ajaxRequests: {},
- ajax: function(param, fnOnSuccess, fnOnError) {
- $.post(
+ ajax: function(param, fnOnSuccess, fnOnError, reqID) {
+ if(reqID !== undefined) {
+ if(LdapWizard.ajaxRequests.hasOwnProperty(reqID)) {
+ LdapWizard.ajaxRequests[reqID].abort();
+ }
+ }
+ var request = $.post(
OC.filePath('user_ldap','ajax','wizard.php'),
param,
function(result) {
- if(result.status == 'success') {
+ if(result.status === 'success') {
fnOnSuccess(result);
} else {
fnOnError(result);
}
}
);
+ if(reqID !== undefined) {
+ LdapWizard.ajaxRequests[reqID] = request;
+ }
},
applyChanges: function (result) {
- for (id in result.changes) {
+ for (var id in result.changes) {
LdapWizard.blacklistAdd(id);
if(id.indexOf('count') > 0) {
$('#'+id).text(result.changes[id]);
@@ -179,28 +188,41 @@ var LdapWizard = {
}
},
+ 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() {
//criterias to continue from the first tab
// - host, port, user filter, agent dn, password, base dn
- host = $('#ldap_host').val();
- port = $('#ldap_port').val();
- agent = $('#ldap_dn').val();
- pwd = $('#ldap_agent_password').val();
- base = $('#ldap_base').val();
+ 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))) {
- $('.ldap_action_continue').removeAttr('disabled');
- $('#ldapSettings').tabs('option', 'disabled', []);
+ LdapWizard.enableTabs();
} else {
- $('.ldap_action_continue').attr('disabled', 'disabled');
- $('#ldapSettings').tabs('option', 'disabled', [1, 2, 3, 4, 5]);
+ LdapWizard.disableTabs();
}
},
blacklistAdd: function(id) {
obj = $('#'+id);
- if(!(obj[0].hasOwnProperty('multiple') && obj[0]['multiple'] == true)) {
+ if(!(obj[0].hasOwnProperty('multiple') && obj[0]['multiple'] === true)) {
//no need to blacklist multiselect
LdapWizard.saveBlacklist[id] = true;
return true;
@@ -244,7 +266,8 @@ var LdapWizard = {
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'
);
}
},
@@ -274,7 +297,8 @@ var LdapWizard = {
LdapWizard.hideSpinner('#ldap_port');
$('#ldap_port').prop('disabled', false);
LdapWizard.showInfoBox(t('user_ldap', 'Please specify the port'));
- }
+ },
+ 'guessPortAndTLS'
);
}
},
@@ -317,27 +341,37 @@ var LdapWizard = {
}
},
- _countThings: function(method) {
+ _countThings: function(method, spinnerID, doneCallback) {
param = 'action='+method+
'&ldap_serverconfig_chooser='+
encodeURIComponent($('#ldap_serverconfig_chooser').val());
- LdapWizard.ajax(param,
+ LdapWizard.showSpinner(spinnerID);
+ var request = LdapWizard.ajax(param,
function(result) {
LdapWizard.applyChanges(result);
+ LdapWizard.hideSpinner(spinnerID);
+ if(doneCallback !== undefined) {
+ doneCallback(method);
+ }
},
function (result) {
- // error handling
- }
+ OC.Notification.show('Counting the entries failed with, ' + result.message);
+ LdapWizard.hideSpinner(spinnerID);
+ if(doneCallback !== undefined) {
+ doneCallback(method);
+ }
+ },
+ method
);
},
- countGroups: function() {
- LdapWizard._countThings('countGroups');
+ countGroups: function(doneCallback) {
+ LdapWizard._countThings('countGroups', '#ldap_group_count', doneCallback);
},
- countUsers: function() {
- LdapWizard._countThings('countUsers');
+ countUsers: function(doneCallback) {
+ LdapWizard._countThings('countUsers', '#ldap_user_count', doneCallback);
},
detectEmailAttribute: function() {
@@ -345,7 +379,7 @@ var LdapWizard = {
'&ldap_serverconfig_chooser='+
encodeURIComponent($('#ldap_serverconfig_chooser').val());
//runs in the background, no callbacks necessary
- LdapWizard.ajax(param, LdapWizard.applyChanges, function(){});
+ LdapWizard.ajax(param, LdapWizard.applyChanges, function(){}, 'detectEmailAttribute');
},
detectGroupMemberAssoc: function() {
@@ -359,7 +393,8 @@ var LdapWizard = {
},
function (result) {
// error handling
- }
+ },
+ 'determineGroupMemberAssoc'
);
},
@@ -372,7 +407,7 @@ var LdapWizard = {
LdapWizard.ajax(param,
function(result) {
$('#ldap_loginfilter_attributes').find('option').remove();
- for (i in result.options['ldap_loginfilter_attributes']) {
+ for (var i in result.options['ldap_loginfilter_attributes']) {
//FIXME: move HTML into template
attr = result.options['ldap_loginfilter_attributes'][i];
$('#ldap_loginfilter_attributes').append(
@@ -392,12 +427,13 @@ var LdapWizard = {
{noneSelectedText : 'No attributes found'});
$('#ldap_loginfilter_attributes').multiselect('disable');
LdapWizard.hideSpinner('#ldap_loginfilter_attributes');
- }
+ },
+ 'determineAttributes'
);
},
findAvailableGroups: function(multisel, type) {
- if(type != 'Users' && type != 'Groups') {
+ if(type !== 'Users' && type !== 'Groups') {
return false;
}
param = 'action=determineGroupsFor'+encodeURIComponent(type)+
@@ -408,7 +444,7 @@ var LdapWizard = {
LdapWizard.ajax(param,
function(result) {
$('#'+multisel).find('option').remove();
- for (i in result.options[multisel]) {
+ for (var i in result.options[multisel]) {
//FIXME: move HTML into template
objc = result.options[multisel][i];
$('#'+multisel).append("<option value='"+objc+"'>"+objc+"</option>");
@@ -435,16 +471,17 @@ var LdapWizard = {
function (result) {
LdapWizard.hideSpinner('#'+multisel);
$('#'+multisel).multiselect('disable');
- if(type == 'Users') {
+ if(type === 'Users') {
LdapWizard.userFilterAvailableGroupsHasRun = true;
LdapWizard.postInitUserFilter();
}
- }
+ },
+ 'findAvailableGroupsFor' + type
);
},
findObjectClasses: function(multisel, type) {
- if(type != 'User' && type != 'Group') {
+ if(type !== 'User' && type !== 'Group') {
return false;
}
param = 'action=determine'+encodeURIComponent(type)+'ObjectClasses'+
@@ -455,7 +492,7 @@ var LdapWizard = {
LdapWizard.ajax(param,
function(result) {
$('#'+multisel).find('option').remove();
- for (i in result.options[multisel]) {
+ for (var i in result.options[multisel]) {
//FIXME: move HTML into template
objc = result.options[multisel][i];
$('#'+multisel).append("<option value='"+objc+"'>"+objc+"</option>");
@@ -476,12 +513,13 @@ var LdapWizard = {
},
function (result) {
LdapWizard.hideSpinner('#'+multisel);
- if(type == 'User') {
+ if(type === 'User') {
LdapWizard.userFilterObjectClassesHasRun = true;
LdapWizard.postInitUserFilter();
}
//TODO: error handling
- }
+ },
+ 'determine' + type + 'ObjectClasses'
);
},
@@ -530,23 +568,21 @@ var LdapWizard = {
isConfigurationActiveControlLocked: true,
init: function() {
+ LdapWizard.instantiateFilters();
+ LdapWizard.admin.setExperienced($('#ldap_experienced_admin').is(':checked'));
LdapWizard.basicStatusCheck();
LdapWizard.functionalityCheck();
LdapWizard.isConfigurationActiveControlLocked = false;
},
initGroupFilter: function() {
- LdapWizard.groupFilter = new LdapFilter('Group');
- LdapWizard.findObjectClasses('ldap_groupfilter_objectclass', 'Group');
- LdapWizard.findAvailableGroups('ldap_groupfilter_groups', 'Groups');
- LdapWizard.countGroups();
+ LdapWizard.groupFilter.activate();
},
/** init login filter tab section **/
initLoginFilter: function() {
- LdapWizard.loginFilter = new LdapFilter('Login');
- LdapWizard.findAttributes();
+ LdapWizard.loginFilter.activate();
},
postInitLoginFilter: function() {
@@ -569,30 +605,80 @@ var LdapWizard = {
});
},
+ 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(mode === LdapWizard.filterModeAssisted) {
+ LdapWizard.groupFilter.updateCount();
+ }
+ LdapWizard.userFilter.findFeatures();
+ });
+ $('#rawUserFilterContainer .ldapGetEntryCount').click(function(event) {
+ event.preventDefault();
+ $('#ldap_user_count').text('');
+ LdapWizard.showSpinner('#rawUserFilterContainer .ldapGetEntryCount');
+ LdapWizard.userFilter.updateCount(LdapWizard.hideTestSpinner);
+ LdapWizard.detectEmailAttribute();
+ $('#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(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);
+ LdapWizard.detectGroupMemberAssoc();
+ $('#ldap_group_count').removeClass('hidden');
+ });
+ },
+
userFilterObjectClassesHasRun: false,
userFilterAvailableGroupsHasRun: false,
initUserFilter: function() {
LdapWizard.userFilterObjectClassesHasRun = false;
LdapWizard.userFilterAvailableGroupsHasRun = false;
- LdapWizard.userFilter = new LdapFilter('User');
- LdapWizard.findObjectClasses('ldap_userfilter_objectclass', 'User');
- LdapWizard.findAvailableGroups('ldap_userfilter_groups', 'Users');
+ LdapWizard.userFilter.activate();
},
postInitUserFilter: function() {
if(LdapWizard.userFilterObjectClassesHasRun &&
LdapWizard.userFilterAvailableGroupsHasRun) {
LdapWizard.userFilter.compose(LdapWizard.detectEmailAttribute);
- LdapWizard.countUsers();
}
},
/** 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;
+ }
newTabIndex = 0;
if(ui.newTab[0].id === '#ldapWizard2') {
LdapWizard.initUserFilter();
@@ -614,10 +700,10 @@ var LdapWizard = {
processChanges: function(triggerObj) {
LdapWizard.hideInfoBox();
- if(triggerObj.id == 'ldap_host'
- || triggerObj.id == 'ldap_port'
- || triggerObj.id == 'ldap_dn'
- || triggerObj.id == 'ldap_agent_password') {
+ 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
@@ -625,16 +711,14 @@ var LdapWizard = {
}
}
- if(triggerObj.id == 'ldap_userlist_filter') {
- LdapWizard.countUsers();
+ if(triggerObj.id === 'ldap_userlist_filter' && !LdapWizard.admin.isExperienced()) {
LdapWizard.detectEmailAttribute();
- } else if(triggerObj.id == 'ldap_group_filter') {
- LdapWizard.countGroups();
+ } else if(triggerObj.id === 'ldap_group_filter' && !LdapWizard.admin.isExperienced()) {
LdapWizard.detectGroupMemberAssoc();
}
- if(triggerObj.id == 'ldap_loginfilter_username'
- || triggerObj.id == 'ldap_loginfilter_email') {
+ if(triggerObj.id === 'ldap_loginfilter_username'
+ || triggerObj.id === 'ldap_loginfilter_email') {
LdapWizard.loginFilter.compose();
}
@@ -663,8 +747,8 @@ var LdapWizard = {
values = values + "\n" + resultObj[i].value;
}
LdapWizard._save($('#'+originalObj)[0], $.trim(values));
- if(originalObj == 'ldap_userfilter_objectclass'
- || originalObj == 'ldap_userfilter_groups') {
+ if(originalObj === 'ldap_userfilter_objectclass'
+ || originalObj === 'ldap_userfilter_groups') {
LdapWizard.userFilter.compose(LdapWizard.detectEmailAttribute);
//when user filter is changed afterwards, login filter needs to
//be adjusted, too
@@ -672,15 +756,19 @@ var LdapWizard = {
LdapWizard.initLoginFilter();
}
LdapWizard.loginFilter.compose();
- } else if(originalObj == 'ldap_loginfilter_attributes') {
+ } else if(originalObj === 'ldap_loginfilter_attributes') {
LdapWizard.loginFilter.compose();
- } else if(originalObj == 'ldap_groupfilter_objectclass'
- || originalObj == 'ldap_groupfilter_groups') {
+ } else if(originalObj === 'ldap_groupfilter_objectclass'
+ || originalObj === 'ldap_groupfilter_groups') {
LdapWizard.groupFilter.compose();
}
},
+ 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'+
@@ -690,10 +778,15 @@ var LdapWizard = {
OC.filePath('user_ldap','ajax','wizard.php'),
param,
function(result) {
- if(result.status == 'success') {
+ LdapWizard.saveProcesses -= 1;
+ if(LdapWizard.saveProcesses === 0) {
+ $('#ldap .ldap_saving').addClass('hidden');
+ $('#ldap *').removeClass('save-cursor');
+ }
+ if(result.status === 'success') {
LdapWizard.processChanges(object);
} else {
-// alert('Oooooooooooh :(');
+ console.log('Could not save value for ' + object.id);
}
}
);
@@ -713,12 +806,15 @@ var LdapWizard = {
},
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') {
+ if($(mg).multiselect().attr('disabled') === 'disabled') {
LdapWizard[stateVar] = 'disable';
} else {
LdapWizard[stateVar] = 'enable';
@@ -726,11 +822,13 @@ var LdapWizard = {
$(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(moc.indexOf('user') >= 0) {
+ if(isUser) {
LdapWizard.blacklistRemove('ldap_userlist_filter');
LdapWizard.userFilter.compose(LdapWizard.detectEmailAttribute);
} else {
@@ -740,47 +838,90 @@ var LdapWizard = {
}
},
+ onToggleRawFilterConfirmation: function(currentMode, callback) {
+ if(!LdapWizard.admin.isExperienced()
+ || currentMode === LdapWizard.filterModeAssisted
+ ) {
+ 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.blacklistRemove('ldap_group_filter');
- LdapWizard.toggleRawFilter('#rawGroupFilterContainer',
- '#ldap_groupfilter_objectclass',
- '#ldap_groupfilter_groups',
- 'groupFilterGroupSelectState',
- 'ldapGroupFilterMode'
- );
+ LdapWizard.onToggleRawFilterConfirmation(
+ LdapWizard.groupFilter.getMode(),
+ 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.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;
- }
- $('#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();
- }
+ LdapWizard.onToggleRawFilterConfirmation(
+ LdapWizard.loginFilter.getMode(),
+ 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.blacklistRemove('ldap_userlist_filter');
- LdapWizard.toggleRawFilter('#rawUserFilterContainer',
- '#ldap_userfilter_objectclass',
- '#ldap_userfilter_groups',
- 'userFilterGroupSelectState',
- 'ldapUserFilterMode'
- );
+ LdapWizard.onToggleRawFilterConfirmation(
+ LdapWizard.userFilter.getMode(),
+ 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) {
@@ -837,6 +978,7 @@ $(document).ready(function() {
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);
@@ -931,4 +1073,10 @@ $(document).ready(function() {
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/lib/configuration.php b/apps/user_ldap/lib/configuration.php
index 4cb00561b3f..28e456ae2ef 100644
--- a/apps/user_ldap/lib/configuration.php
+++ b/apps/user_ldap/lib/configuration.php
@@ -69,6 +69,7 @@ class Configuration {
'ldapConfigurationActive' => false,
'ldapAttributesForUserSearch' => null,
'ldapAttributesForGroupSearch' => null,
+ 'ldapExperiencedAdmin' => false,
'homeFolderNamingRule' => null,
'hasPagedResultSupport' => false,
'hasMemberOfFilterSupport' => false,
@@ -345,52 +346,53 @@ class Configuration {
*/
public function getDefaults() {
return array(
- 'ldap_host' => '',
- 'ldap_port' => '',
- 'ldap_backup_host' => '',
- 'ldap_backup_port' => '',
- 'ldap_override_main_server' => '',
- 'ldap_dn' => '',
- 'ldap_agent_password' => '',
- 'ldap_base' => '',
- 'ldap_base_users' => '',
- 'ldap_base_groups' => '',
- 'ldap_userlist_filter' => '',
- 'ldap_user_filter_mode' => 0,
- 'ldap_userfilter_objectclass' => '',
- 'ldap_userfilter_groups' => '',
- 'ldap_login_filter' => '',
- 'ldap_login_filter_mode' => 0,
- 'ldap_loginfilter_email' => 0,
- 'ldap_loginfilter_username' => 1,
- 'ldap_loginfilter_attributes' => '',
- 'ldap_group_filter' => '',
- 'ldap_group_filter_mode' => 0,
- 'ldap_groupfilter_objectclass' => '',
- 'ldap_groupfilter_groups' => '',
- 'ldap_display_name' => 'displayName',
- 'ldap_group_display_name' => 'cn',
- 'ldap_tls' => 1,
- 'ldap_nocase' => 0,
- 'ldap_quota_def' => '',
- 'ldap_quota_attr' => '',
- 'ldap_email_attr' => '',
- 'ldap_group_member_assoc_attribute' => 'uniqueMember',
- 'ldap_cache_ttl' => 600,
- 'ldap_uuid_user_attribute' => 'auto',
- 'ldap_uuid_group_attribute' => 'auto',
- 'home_folder_naming_rule' => '',
- 'ldap_turn_off_cert_check' => 0,
- 'ldap_configuration_active' => 0,
- 'ldap_attributes_for_user_search' => '',
- 'ldap_attributes_for_group_search' => '',
- 'ldap_expert_username_attr' => '',
- 'ldap_expert_uuid_user_attr' => '',
- 'ldap_expert_uuid_group_attr' => '',
- 'has_memberof_filter_support' => 0,
- 'last_jpegPhoto_lookup' => 0,
- 'ldap_nested_groups' => 0,
- 'ldap_paging_size' => 500,
+ 'ldap_host' => '',
+ 'ldap_port' => '',
+ 'ldap_backup_host' => '',
+ 'ldap_backup_port' => '',
+ 'ldap_override_main_server' => '',
+ 'ldap_dn' => '',
+ 'ldap_agent_password' => '',
+ 'ldap_base' => '',
+ 'ldap_base_users' => '',
+ 'ldap_base_groups' => '',
+ 'ldap_userlist_filter' => '',
+ 'ldap_user_filter_mode' => 0,
+ 'ldap_userfilter_objectclass' => '',
+ 'ldap_userfilter_groups' => '',
+ 'ldap_login_filter' => '',
+ 'ldap_login_filter_mode' => 0,
+ 'ldap_loginfilter_email' => 0,
+ 'ldap_loginfilter_username' => 1,
+ 'ldap_loginfilter_attributes' => '',
+ 'ldap_group_filter' => '',
+ 'ldap_group_filter_mode' => 0,
+ 'ldap_groupfilter_objectclass' => '',
+ 'ldap_groupfilter_groups' => '',
+ 'ldap_display_name' => 'displayName',
+ 'ldap_group_display_name' => 'cn',
+ 'ldap_tls' => 1,
+ 'ldap_nocase' => 0,
+ 'ldap_quota_def' => '',
+ 'ldap_quota_attr' => '',
+ 'ldap_email_attr' => '',
+ 'ldap_group_member_assoc_attribute' => 'uniqueMember',
+ 'ldap_cache_ttl' => 600,
+ 'ldap_uuid_user_attribute' => 'auto',
+ 'ldap_uuid_group_attribute' => 'auto',
+ 'home_folder_naming_rule' => '',
+ 'ldap_turn_off_cert_check' => 0,
+ 'ldap_configuration_active' => 0,
+ 'ldap_attributes_for_user_search' => '',
+ 'ldap_attributes_for_group_search' => '',
+ 'ldap_expert_username_attr' => '',
+ 'ldap_expert_uuid_user_attr' => '',
+ 'ldap_expert_uuid_group_attr' => '',
+ 'has_memberof_filter_support' => 0,
+ 'last_jpegPhoto_lookup' => 0,
+ 'ldap_nested_groups' => 0,
+ 'ldap_paging_size' => 500,
+ 'ldap_experienced_admin' => 0,
);
}
@@ -400,50 +402,51 @@ class Configuration {
public function getConfigTranslationArray() {
//TODO: merge them into one representation
static $array = array(
- 'ldap_host' => 'ldapHost',
- 'ldap_port' => 'ldapPort',
- 'ldap_backup_host' => 'ldapBackupHost',
- 'ldap_backup_port' => 'ldapBackupPort',
- 'ldap_override_main_server' => 'ldapOverrideMainServer',
- 'ldap_dn' => 'ldapAgentName',
- 'ldap_agent_password' => 'ldapAgentPassword',
- 'ldap_base' => 'ldapBase',
- 'ldap_base_users' => 'ldapBaseUsers',
- 'ldap_base_groups' => 'ldapBaseGroups',
- 'ldap_userfilter_objectclass' => 'ldapUserFilterObjectclass',
- 'ldap_userfilter_groups' => 'ldapUserFilterGroups',
- 'ldap_userlist_filter' => 'ldapUserFilter',
- 'ldap_user_filter_mode' => 'ldapUserFilterMode',
- 'ldap_login_filter' => 'ldapLoginFilter',
- 'ldap_login_filter_mode' => 'ldapLoginFilterMode',
- 'ldap_loginfilter_email' => 'ldapLoginFilterEmail',
- 'ldap_loginfilter_username' => 'ldapLoginFilterUsername',
- 'ldap_loginfilter_attributes' => 'ldapLoginFilterAttributes',
- 'ldap_group_filter' => 'ldapGroupFilter',
- 'ldap_group_filter_mode' => 'ldapGroupFilterMode',
- 'ldap_groupfilter_objectclass' => 'ldapGroupFilterObjectclass',
- 'ldap_groupfilter_groups' => 'ldapGroupFilterGroups',
- 'ldap_display_name' => 'ldapUserDisplayName',
- 'ldap_group_display_name' => 'ldapGroupDisplayName',
- 'ldap_tls' => 'ldapTLS',
- 'ldap_nocase' => 'ldapNoCase',
- 'ldap_quota_def' => 'ldapQuotaDefault',
- 'ldap_quota_attr' => 'ldapQuotaAttribute',
- 'ldap_email_attr' => 'ldapEmailAttribute',
- 'ldap_group_member_assoc_attribute' => 'ldapGroupMemberAssocAttr',
- 'ldap_cache_ttl' => 'ldapCacheTTL',
- 'home_folder_naming_rule' => 'homeFolderNamingRule',
- 'ldap_turn_off_cert_check' => 'turnOffCertCheck',
- 'ldap_configuration_active' => 'ldapConfigurationActive',
- 'ldap_attributes_for_user_search' => 'ldapAttributesForUserSearch',
- 'ldap_attributes_for_group_search' => 'ldapAttributesForGroupSearch',
- 'ldap_expert_username_attr' => 'ldapExpertUsernameAttr',
- 'ldap_expert_uuid_user_attr' => 'ldapExpertUUIDUserAttr',
- 'ldap_expert_uuid_group_attr' => 'ldapExpertUUIDGroupAttr',
- 'has_memberof_filter_support' => 'hasMemberOfFilterSupport',
- 'last_jpegPhoto_lookup' => 'lastJpegPhotoLookup',
+ 'ldap_host' => 'ldapHost',
+ 'ldap_port' => 'ldapPort',
+ 'ldap_backup_host' => 'ldapBackupHost',
+ 'ldap_backup_port' => 'ldapBackupPort',
+ 'ldap_override_main_server' => 'ldapOverrideMainServer',
+ 'ldap_dn' => 'ldapAgentName',
+ 'ldap_agent_password' => 'ldapAgentPassword',
+ 'ldap_base' => 'ldapBase',
+ 'ldap_base_users' => 'ldapBaseUsers',
+ 'ldap_base_groups' => 'ldapBaseGroups',
+ 'ldap_userfilter_objectclass' => 'ldapUserFilterObjectclass',
+ 'ldap_userfilter_groups' => 'ldapUserFilterGroups',
+ 'ldap_userlist_filter' => 'ldapUserFilter',
+ 'ldap_user_filter_mode' => 'ldapUserFilterMode',
+ 'ldap_login_filter' => 'ldapLoginFilter',
+ 'ldap_login_filter_mode' => 'ldapLoginFilterMode',
+ 'ldap_loginfilter_email' => 'ldapLoginFilterEmail',
+ 'ldap_loginfilter_username' => 'ldapLoginFilterUsername',
+ 'ldap_loginfilter_attributes' => 'ldapLoginFilterAttributes',
+ 'ldap_group_filter' => 'ldapGroupFilter',
+ 'ldap_group_filter_mode' => 'ldapGroupFilterMode',
+ 'ldap_groupfilter_objectclass' => 'ldapGroupFilterObjectclass',
+ 'ldap_groupfilter_groups' => 'ldapGroupFilterGroups',
+ 'ldap_display_name' => 'ldapUserDisplayName',
+ 'ldap_group_display_name' => 'ldapGroupDisplayName',
+ 'ldap_tls' => 'ldapTLS',
+ 'ldap_nocase' => 'ldapNoCase',
+ 'ldap_quota_def' => 'ldapQuotaDefault',
+ 'ldap_quota_attr' => 'ldapQuotaAttribute',
+ 'ldap_email_attr' => 'ldapEmailAttribute',
+ 'ldap_group_member_assoc_attribute' => 'ldapGroupMemberAssocAttr',
+ 'ldap_cache_ttl' => 'ldapCacheTTL',
+ 'home_folder_naming_rule' => 'homeFolderNamingRule',
+ 'ldap_turn_off_cert_check' => 'turnOffCertCheck',
+ 'ldap_configuration_active' => 'ldapConfigurationActive',
+ 'ldap_attributes_for_user_search' => 'ldapAttributesForUserSearch',
+ 'ldap_attributes_for_group_search' => 'ldapAttributesForGroupSearch',
+ 'ldap_expert_username_attr' => 'ldapExpertUsernameAttr',
+ 'ldap_expert_uuid_user_attr' => 'ldapExpertUUIDUserAttr',
+ 'ldap_expert_uuid_group_attr' => 'ldapExpertUUIDGroupAttr',
+ 'has_memberof_filter_support' => 'hasMemberOfFilterSupport',
+ 'last_jpegPhoto_lookup' => 'lastJpegPhotoLookup',
'ldap_nested_groups' => 'ldapNestedGroups',
'ldap_paging_size' => 'ldapPagingSize',
+ 'ldap_experienced_admin' => 'ldapExperiencedAdmin'
);
return $array;
}
diff --git a/apps/user_ldap/settings.php b/apps/user_ldap/settings.php
index e7cdd0d926a..1e588b1cd85 100644
--- a/apps/user_ldap/settings.php
+++ b/apps/user_ldap/settings.php
@@ -26,6 +26,7 @@
OC_Util::checkAdminUser();
OCP\Util::addScript('user_ldap', 'ldapFilter');
+OCP\Util::addScript('user_ldap', 'experiencedAdmin');
OCP\Util::addScript('user_ldap', 'settings');
OCP\Util::addScript('core', 'jquery.multiselect');
OCP\Util::addStyle('user_ldap', 'settings');
diff --git a/apps/user_ldap/templates/part.wizard-groupfilter.php b/apps/user_ldap/templates/part.wizard-groupfilter.php
index e460997b1bf..1953d2eaa6e 100644
--- a/apps/user_ldap/templates/part.wizard-groupfilter.php
+++ b/apps/user_ldap/templates/part.wizard-groupfilter.php
@@ -30,13 +30,16 @@
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()));?>"
/>
+ <button class="ldapGetEntryCount hidden" name="ldapGetEntryCount" type="button">
+ <?php p($l->t('Test Filter'));?>
+ </button>
</p>
<p>
<div class="ldapWizardInfo invisible">&nbsp;</div>
</p>
- <p>
+ <p class="ldap_count">
<span id="ldap_group_count">0 <?php p($l->t('groups found'));?></span>
</p>
<?php print_unescaped($_['wizardControls']); ?>
</div>
-</fieldset> \ No newline at end of file
+</fieldset>
diff --git a/apps/user_ldap/templates/part.wizard-server.php b/apps/user_ldap/templates/part.wizard-server.php
index bee2b874178..c1744143f98 100644
--- a/apps/user_ldap/templates/part.wizard-server.php
+++ b/apps/user_ldap/templates/part.wizard-server.php
@@ -69,6 +69,16 @@
</textarea>
</div>
+ <div class="tablerow left">
+ <input type="checkbox" id="ldap_experienced_admin" value="1"
+ name="ldap_experienced_admin" class="tablecell lwautosave"
+ 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">
+ <?php p($l->t('Manually enter LDAP filters (recommended for large directories)'));?>
+ </label>
+ </div>
+
<div class="tablerow">
<div class="tablecell ldapWizardInfo invisible">&nbsp;
</div>
diff --git a/apps/user_ldap/templates/part.wizard-userfilter.php b/apps/user_ldap/templates/part.wizard-userfilter.php
index eff9f89ce2c..99a6e75370b 100644
--- a/apps/user_ldap/templates/part.wizard-userfilter.php
+++ b/apps/user_ldap/templates/part.wizard-userfilter.php
@@ -30,13 +30,16 @@
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>
</p>
<p>
<div class="ldapWizardInfo invisible">&nbsp;</div>
</p>
- <p>
+ <p class="ldap_count">
<span id="ldap_user_count">0 <?php p($l->t('users found'));?></span>
</p>
<?php print_unescaped($_['wizardControls']); ?>
</div>
-</fieldset> \ No newline at end of file
+</fieldset>
diff --git a/apps/user_ldap/templates/part.wizardcontrols.php b/apps/user_ldap/templates/part.wizardcontrols.php
index 33e1614c9c6..90d558e72d1 100644
--- a/apps/user_ldap/templates/part.wizardcontrols.php
+++ b/apps/user_ldap/templates/part.wizardcontrols.php
@@ -1,4 +1,5 @@
<div class="ldapWizardControls">
+ <span class="ldap_saving hidden"><?php p($l->t('Saving'));?> <img class="wizSpinner" src="<?php p(image_path('core', 'loading.gif')); ?>"/></span>
<span class="ldap_config_state_indicator"></span> <span class="ldap_config_state_indicator_sign"></span>
<button class="ldap_action_back invisible" name="ldap_action_back"
type="button">
diff --git a/lib/private/server.php b/lib/private/server.php
index 7fa06298b29..ff34cfdccb6 100644
--- a/lib/private/server.php
+++ b/lib/private/server.php
@@ -14,6 +14,7 @@ use OC\Security\Crypto;
use OC\Security\SecureRandom;
use OCP\IServerContainer;
use OCP\ISession;
+use OC\Tagging\TagMapper;
/**
* Class Server
@@ -68,9 +69,13 @@ class Server extends SimpleContainer implements IServerContainer {
$this->registerService('PreviewManager', function ($c) {
return new PreviewManager();
});
+ $this->registerService('TagMapper', function($c) {
+ return new TagMapper($c->getDb());
+ });
$this->registerService('TagManager', function ($c) {
+ $tagMapper = $c->query('TagMapper');
$user = \OC_User::getUser();
- return new TagManager($user);
+ return new TagManager($tagMapper, $user);
});
$this->registerService('RootFolder', function ($c) {
// TODO: get user and user manager from container as well
diff --git a/lib/private/share/share.php b/lib/private/share/share.php
index 5314e09b8de..b827b84a9bc 100644
--- a/lib/private/share/share.php
+++ b/lib/private/share/share.php
@@ -1181,7 +1181,7 @@ class Share extends \OC\Share\Constants {
}
}
// TODO Add option for collections to be collection of themselves, only 'folder' does it now...
- if (!self::getBackend($itemType) instanceof \OCP\Share_Backend_Collection || $itemType != 'folder') {
+ if (isset(self::$backendTypes[$itemType]) && (!self::getBackend($itemType) instanceof \OCP\Share_Backend_Collection || $itemType != 'folder')) {
unset($collectionTypes[0]);
}
// Return array if collections were found or the item type is a
@@ -1193,6 +1193,57 @@ class Share extends \OC\Share\Constants {
}
/**
+ * Get the owners of items shared with a user.
+ *
+ * @param string $user The user the items are shared with.
+ * @param string $type The type of the items shared with the user.
+ * @param boolean $includeCollections Include collection item types (optional)
+ * @param boolean $includeOwner include owner in the list of users the item is shared with (optional)
+ * @return array
+ */
+ public static function getSharedItemsOwners($user, $type, $includeCollections = false, $includeOwner = false) {
+ // First, we find out if $type is part of a collection (and if that collection is part of
+ // another one and so on).
+ $collectionTypes = array();
+ if (!$includeCollections || !$collectionTypes = self::getCollectionItemTypes($type)) {
+ $collectionTypes[] = $type;
+ }
+
+ // Of these collection types, along with our original $type, we make a
+ // list of the ones for which a sharing backend has been registered.
+ // FIXME: Ideally, we wouldn't need to nest getItemsSharedWith in this loop but just call it
+ // with its $includeCollections parameter set to true. Unfortunately, this fails currently.
+ $allMaybeSharedItems = array();
+ foreach ($collectionTypes as $collectionType) {
+ if (isset(self::$backends[$collectionType])) {
+ $allMaybeSharedItems[$collectionType] = self::getItemsSharedWithUser(
+ $collectionType,
+ $user,
+ self::FORMAT_NONE
+ );
+ }
+ }
+
+ $owners = array();
+ if ($includeOwner) {
+ $owners[] = $user;
+ }
+
+ // We take a look at all shared items of the given $type (or of the collections it is part of)
+ // and find out their owners. Then, we gather the tags for the original $type from all owners,
+ // and return them as elements of a list that look like "Tag (owner)".
+ foreach ($allMaybeSharedItems as $collectionType => $maybeSharedItems) {
+ foreach ($maybeSharedItems as $sharedItem) {
+ if (isset($sharedItem['id'])) { //workaround for https://github.com/owncloud/core/issues/2814
+ $owners[] = $sharedItem['uid_owner'];
+ }
+ }
+ }
+
+ return $owners;
+ }
+
+ /**
* Get shared items from the database
* @param string $itemType
* @param string $item Item source or target (optional)
diff --git a/lib/private/tagging/tag.php b/lib/private/tagging/tag.php
new file mode 100644
index 00000000000..3ea9fbac20b
--- /dev/null
+++ b/lib/private/tagging/tag.php
@@ -0,0 +1,89 @@
+<?php
+/**
+* ownCloud - Tag class
+*
+* @author Bernhard Reiter
+* @copyright 2014 Bernhard Reiter <ockham@raz.or.at>
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
+* License as published by the Free Software Foundation; either
+* version 3 of the License, or any later version.
+*
+* This library is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
+*
+* You should have received a copy of the GNU Affero General Public
+* License along with this library. If not, see <http://www.gnu.org/licenses/>.
+*
+*/
+
+namespace OC\Tagging;
+
+use \OCP\AppFramework\Db\Entity;
+
+/**
+ * Class to represent a tag.
+ *
+ * @method string getOwner()
+ * @method void setOwner(string $owner)
+ * @method string getType()
+ * @method void setType(string $type)
+ * @method string getName()
+ * @method void setName(string $name)
+ */
+class Tag extends Entity {
+
+ protected $owner;
+ protected $type;
+ protected $name;
+
+ /**
+ * Constructor.
+ *
+ * @param string $owner The tag's owner
+ * @param string $type The type of item this tag is used for
+ * @param string $name The tag's name
+ */
+ public function __construct($owner = null, $type = null, $name = null) {
+ $this->setOwner($owner);
+ $this->setType($type);
+ $this->setName($name);
+ }
+
+ /**
+ * Transform a database columnname to a property
+ *
+ * @param string $columnName the name of the column
+ * @return string the property name
+ * @todo migrate existing database columns to the correct names
+ * to be able to drop this direct mapping
+ */
+ public function columnToProperty($columnName){
+ if ($columnName === 'category') {
+ return 'name';
+ } elseif ($columnName === 'uid') {
+ return 'owner';
+ } else {
+ return parent::columnToProperty($columnName);
+ }
+ }
+
+ /**
+ * Transform a property to a database column name
+ *
+ * @param string $property the name of the property
+ * @return string the column name
+ */
+ public function propertyToColumn($property){
+ if ($property === 'name') {
+ return 'category';
+ } elseif ($property === 'owner') {
+ return 'uid';
+ } else {
+ return parent::propertyToColumn($property);
+ }
+ }
+}
diff --git a/lib/private/tagging/tagmapper.php b/lib/private/tagging/tagmapper.php
new file mode 100644
index 00000000000..6c9bec7aa52
--- /dev/null
+++ b/lib/private/tagging/tagmapper.php
@@ -0,0 +1,77 @@
+<?php
+/**
+* ownCloud - TagMapper class
+*
+* @author Bernhard Reiter
+* @copyright 2014 Bernhard Reiter <ockham@raz.or.at>
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
+* License as published by the Free Software Foundation; either
+* version 3 of the License, or any later version.
+*
+* This library is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
+*
+* You should have received a copy of the GNU Affero General Public
+* License along with this library. If not, see <http://www.gnu.org/licenses/>.
+*
+*/
+
+namespace OC\Tagging;
+
+use \OCP\AppFramework\Db\Mapper,
+ \OCP\AppFramework\Db\DoesNotExistException,
+ \OCP\IDb;
+
+/**
+ * Mapper for Tag entity
+ */
+class TagMapper extends Mapper {
+
+ /**
+ * Constructor.
+ *
+ * @param IDb $db Instance of the Db abstraction layer.
+ */
+ public function __construct(IDb $db) {
+ parent::__construct($db, 'vcategory', 'OC\Tagging\Tag');
+ }
+
+ /**
+ * Load tags from the database.
+ *
+ * @param array|string $owners The user(s) whose tags we are going to load.
+ * @param string $type The type of item for which we are loading tags.
+ * @return array An array of Tag objects.
+ */
+ public function loadTags($owners, $type) {
+ if(!is_array($owners)) {
+ $owners = array($owners);
+ }
+
+ $sql = 'SELECT `id`, `uid`, `type`, `category` FROM `' . $this->getTableName() . '` '
+ . 'WHERE `uid` IN (' . str_repeat('?,', count($owners)-1) . '?) AND `type` = ? ORDER BY `category`';
+ return $this->findEntities($sql, array_merge($owners, array($type)));
+ }
+
+ /**
+ * Check if a given Tag object already exists in the database.
+ *
+ * @param Tag $tag The tag to look for in the database.
+ * @return bool
+ */
+ public function tagExists($tag) {
+ $sql = 'SELECT `id`, `uid`, `type`, `category` FROM `' . $this->getTableName() . '` '
+ . 'WHERE `uid` = ? AND `type` = ? AND `category` = ?';
+ try {
+ $this->findEntity($sql, array($tag->getOwner(), $tag->getType(), $tag->getName()));
+ } catch (DoesNotExistException $e) {
+ return false;
+ }
+ return true;
+ }
+}
+
diff --git a/lib/private/tagmanager.php b/lib/private/tagmanager.php
index 9a371a11253..d5bff04acff 100644
--- a/lib/private/tagmanager.php
+++ b/lib/private/tagmanager.php
@@ -33,6 +33,8 @@
namespace OC;
+use OC\Tagging\TagMapper;
+
class TagManager implements \OCP\ITagManager {
/**
@@ -40,15 +42,24 @@ class TagManager implements \OCP\ITagManager {
*
* @var string
*/
- private $user = null;
+ private $user;
+
+ /**
+ * TagMapper
+ *
+ * @var TagMapper
+ */
+ private $mapper;
/**
* Constructor.
*
- * @param string $user The user whos data the object will operate on.
+ * @param TagMapper $mapper Instance of the TagMapper abstraction layer.
+ * @param string $user The user whose data the object will operate on.
*/
- public function __construct($user) {
+ public function __construct(TagMapper $mapper, $user) {
+ $this->mapper = $mapper;
$this->user = $user;
}
@@ -59,10 +70,11 @@ class TagManager implements \OCP\ITagManager {
* @see \OCP\ITags
* @param string $type The type identifier e.g. 'contact' or 'event'.
* @param array $defaultTags An array of default tags to be used if none are stored.
+ * @param boolean $includeShared Whether to include tags for items shared with this user by others.
* @return \OCP\ITags
*/
- public function load($type, $defaultTags=array()) {
- return new Tags($this->user, $type, $defaultTags);
+ public function load($type, $defaultTags=array(), $includeShared=false) {
+ return new Tags($this->mapper, $this->user, $type, $defaultTags, $includeShared);
}
-} \ No newline at end of file
+}
diff --git a/lib/private/tags.php b/lib/private/tags.php
index 0e58789ecd5..bab3d495282 100644
--- a/lib/private/tags.php
+++ b/lib/private/tags.php
@@ -34,6 +34,9 @@
namespace OC;
+use \OC\Tagging\Tag,
+ \OC\Tagging\TagMapper;
+
class Tags implements \OCP\ITags {
/**
@@ -55,14 +58,44 @@ class Tags implements \OCP\ITags {
*
* @var string
*/
- private $type = null;
+ private $type;
/**
* User
*
* @var string
*/
- private $user = null;
+ private $user;
+
+ /**
+ * Are we including tags for shared items?
+ *
+ * @var bool
+ */
+ private $includeShared = false;
+
+ /**
+ * The current user, plus any owners of the items shared with the current
+ * user, if $this->includeShared === true.
+ *
+ * @var array
+ */
+ private $owners = array();
+
+ /**
+ * The Mapper we're using to communicate our Tag objects to the database.
+ *
+ * @var TagMapper
+ */
+ private $mapper;
+
+ /**
+ * The sharing backend for objects of $this->type. Required if
+ * $this->includeShared === true to determine ownership of items.
+ *
+ * @var \OCP\Share_Backend
+ */
+ private $backend;
const TAG_TABLE = '*PREFIX*vcategory';
const RELATION_TABLE = '*PREFIX*vcategory_to_object';
@@ -72,47 +105,29 @@ class Tags implements \OCP\ITags {
/**
* Constructor.
*
- * @param string $user The user whos data the object will operate on.
- * @param string $type
+ * @param TagMapper $mapper Instance of the TagMapper abstraction layer.
+ * @param string $user The user whose data the object will operate on.
+ * @param string $type The type of items for which tags will be loaded.
+ * @param array $defaultTags Tags that should be created at construction.
+ * @param boolean $includeShared Whether to include tags for items shared with this user by others.
*/
- public function __construct($user, $type, $defaultTags = array()) {
+ public function __construct(TagMapper $mapper, $user, $type, $defaultTags = array(), $includeShared = false) {
+ $this->mapper = $mapper;
$this->user = $user;
$this->type = $type;
- $this->loadTags($defaultTags);
- }
-
- /**
- * Load tags from db.
- *
- */
- protected function loadTags($defaultTags=array()) {
- $this->tags = array();
- $result = null;
- $sql = 'SELECT `id`, `category` FROM `' . self::TAG_TABLE . '` '
- . 'WHERE `uid` = ? AND `type` = ? ORDER BY `category`';
- try {
- $stmt = \OCP\DB::prepare($sql);
- $result = $stmt->execute(array($this->user, $this->type));
- if (\OCP\DB::isError($result)) {
- \OCP\Util::writeLog('core', __METHOD__. ', DB error: ' . \OCP\DB::getErrorMessage($result), \OCP\Util::ERROR);
- }
- } catch(\Exception $e) {
- \OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(),
- \OCP\Util::ERROR);
- }
-
- if(!is_null($result)) {
- while( $row = $result->fetchRow()) {
- $this->tags[$row['id']] = $row['category'];
- }
+ $this->includeShared = $includeShared;
+ $this->owners = array($this->user);
+ if ($this->includeShared) {
+ $this->owners = array_merge($this->owners, \OC\Share\Share::getSharedItemsOwners($this->user, $this->type, true));
+ $this->backend = \OC\Share\Share::getBackend($this->type);
}
+ $this->tags = $this->mapper->loadTags($this->owners, $this->type);
if(count($defaultTags) > 0 && count($this->tags) === 0) {
$this->addMultiple($defaultTags, true);
}
\OCP\Util::writeLog('core', __METHOD__.', tags: ' . print_r($this->tags, true),
\OCP\Util::DEBUG);
-
}
/**
@@ -125,12 +140,27 @@ class Tags implements \OCP\ITags {
}
/**
+ * Returns an array mapping a given tag's properties to its values:
+ * ['id' => 0, 'name' = 'Tag', 'owner' = 'User', 'type' => 'tagtype']
+ *
+ * @param string $id The ID of the tag that is going to be mapped
+ * @return array|false
+ */
+ public function getTag($id) {
+ $key = $this->getTagById($id);
+ if ($key !== false) {
+ return $this->tagMap($this->tags[$key]);
+ }
+ return false;
+ }
+
+ /**
* Get the tags for a specific user.
*
- * This returns an array with id/name maps:
+ * This returns an array with maps containing each tag's properties:
* [
- * ['id' => 0, 'name' = 'First tag'],
- * ['id' => 1, 'name' = 'Second tag'],
+ * ['id' => 0, 'name' = 'First tag', 'owner' = 'User', 'type' => 'tagtype'],
+ * ['id' => 1, 'name' = 'Shared tag', 'owner' = 'Other user', 'type' => 'tagtype'],
* ]
*
* @return array
@@ -140,16 +170,14 @@ class Tags implements \OCP\ITags {
return array();
}
- $tags = array_values($this->tags);
- uasort($tags, 'strnatcasecmp');
+ usort($this->tags, function($a, $b) {
+ return strnatcasecmp($a->getName(), $b->getName());
+ });
$tagMap = array();
- foreach($tags as $tag) {
- if($tag !== self::TAG_FAVORITE) {
- $tagMap[] = array(
- 'id' => $this->array_searchi($tag, $this->tags),
- 'name' => $tag
- );
+ foreach($this->tags as $tag) {
+ if($tag->getName() !== self::TAG_FAVORITE) {
+ $tagMap[] = $this->tagMap($tag);
}
}
return $tagMap;
@@ -157,6 +185,21 @@ class Tags implements \OCP\ITags {
}
/**
+ * Return only the tags owned by the given user, omitting any tags shared
+ * by other users.
+ *
+ * @param string $user The user whose tags are to be checked.
+ * @return array An array of Tag objects.
+ */
+ public function getTagsForUser($user) {
+ return array_filter($this->tags,
+ function($tag) use($user) {
+ return $tag->getOwner() === $user;
+ }
+ );
+ }
+
+ /**
* Get the a list if items tagged with $tag.
*
* Throws an exception if the tag could not be found.
@@ -174,7 +217,7 @@ class Tags implements \OCP\ITags {
\OCP\Util::writeLog('core', __METHOD__.', Cannot use empty tag names', \OCP\Util::DEBUG);
return false;
}
- $tagId = $this->array_searchi($tag, $this->tags);
+ $tagId = $this->getTagId($tag);
}
if($tagId === false) {
@@ -203,7 +246,22 @@ class Tags implements \OCP\ITags {
if(!is_null($result)) {
while( $row = $result->fetchRow()) {
- $ids[] = (int)$row['objid'];
+ $id = (int)$row['objid'];
+
+ if ($this->includeShared) {
+ // We have to check if we are really allowed to access the
+ // items that are tagged with $tag. To that end, we ask the
+ // corresponding sharing backend if the item identified by $id
+ // is owned by any of $this->owners.
+ foreach ($this->owners as $owner) {
+ if ($this->backend->isValidSource($id, $owner)) {
+ $ids[] = $id;
+ break;
+ }
+ }
+ } else {
+ $ids[] = $id;
+ }
}
}
@@ -211,13 +269,26 @@ class Tags implements \OCP\ITags {
}
/**
- * Checks whether a tag is already saved.
+ * Checks whether a tag is saved for the given user,
+ * disregarding the ones shared with him or her.
+ *
+ * @param string $name The tag name to check for.
+ * @param string $user The user whose tags are to be checked.
+ * @return bool
+ */
+ public function userHasTag($name, $user) {
+ $key = $this->array_searchi($name, $this->getTagsForUser($user));
+ return ($key !== false) ? $this->tags[$key]->getId() : false;
+ }
+
+ /**
+ * Checks whether a tag is saved for or shared with the current user.
*
- * @param string $name The name to check for.
+ * @param string $name The tag name to check for.
* @return bool
*/
public function hasTag($name) {
- return $this->in_arrayi($name, $this->tags);
+ return $this->getTagId($name) !== false;
}
/**
@@ -233,41 +304,27 @@ class Tags implements \OCP\ITags {
\OCP\Util::writeLog('core', __METHOD__.', Cannot add an empty tag', \OCP\Util::DEBUG);
return false;
}
- if($this->hasTag($name)) {
+ if($this->userHasTag($name, $this->user)) {
\OCP\Util::writeLog('core', __METHOD__.', name: ' . $name. ' exists already', \OCP\Util::DEBUG);
return false;
}
try {
- $result = \OCP\DB::insertIfNotExist(
- self::TAG_TABLE,
- array(
- 'uid' => $this->user,
- 'type' => $this->type,
- 'category' => $name,
- )
- );
- if (\OCP\DB::isError($result)) {
- \OCP\Util::writeLog('core', __METHOD__. 'DB error: ' . \OCP\DB::getErrorMessage($result), \OCP\Util::ERROR);
- return false;
- } elseif((int)$result === 0) {
- \OCP\Util::writeLog('core', __METHOD__.', Tag already exists: ' . $name, \OCP\Util::DEBUG);
- return false;
- }
+ $tag = new Tag($this->user, $this->type, $name);
+ $tag = $this->mapper->insert($tag);
+ $this->tags[] = $tag;
} catch(\Exception $e) {
\OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(),
\OCP\Util::ERROR);
return false;
}
- $id = \OCP\DB::insertid(self::TAG_TABLE);
- \OCP\Util::writeLog('core', __METHOD__.', id: ' . $id, \OCP\Util::DEBUG);
- $this->tags[$id] = $name;
- return $id;
+ \OCP\Util::writeLog('core', __METHOD__.', id: ' . $tag->getId(), \OCP\Util::DEBUG);
+ return $tag->getId();
}
/**
* Rename tag.
*
- * @param string $from The name of the existing tag
+ * @param string|integer $from The name or ID of the existing tag
* @param string $to The new name of the tag.
* @return bool
*/
@@ -280,27 +337,30 @@ class Tags implements \OCP\ITags {
return false;
}
- $id = $this->array_searchi($from, $this->tags);
- if($id === false) {
+ if (is_numeric($from)) {
+ $key = $this->getTagById($from);
+ } else {
+ $key = $this->getTagByName($from);
+ }
+ if($key === false) {
\OCP\Util::writeLog('core', __METHOD__.', tag: ' . $from. ' does not exist', \OCP\Util::DEBUG);
return false;
}
+ $tag = $this->tags[$key];
+
+ if($this->userHasTag($to, $tag->getOwner())) {
+ \OCP\Util::writeLog('core', __METHOD__.', A tag named ' . $to. ' already exists for user ' . $tag->getOwner() . '.', \OCP\Util::DEBUG);
+ return false;
+ }
- $sql = 'UPDATE `' . self::TAG_TABLE . '` SET `category` = ? '
- . 'WHERE `uid` = ? AND `type` = ? AND `id` = ?';
try {
- $stmt = \OCP\DB::prepare($sql);
- $result = $stmt->execute(array($to, $this->user, $this->type, $id));
- if (\OCP\DB::isError($result)) {
- \OCP\Util::writeLog('core', __METHOD__. 'DB error: ' . \OCP\DB::getErrorMessage($result), \OCP\Util::ERROR);
- return false;
- }
+ $tag->setName($to);
+ $this->tags[$key] = $this->mapper->update($tag);
} catch(\Exception $e) {
\OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(),
\OCP\Util::ERROR);
return false;
}
- $this->tags[$id] = $to;
return true;
}
@@ -308,7 +368,7 @@ class Tags implements \OCP\ITags {
* Add a list of new tags.
*
* @param string[] $names A string with a name or an array of strings containing
- * the name(s) of the to add.
+ * the name(s) of the tag(s) to add.
* @param bool $sync When true, save the tags
* @param int|null $id int Optional object id to add to this|these tag(s)
* @return bool Returns false on error.
@@ -322,9 +382,8 @@ class Tags implements \OCP\ITags {
$newones = array();
foreach($names as $name) {
- if(($this->in_arrayi(
- $name, $this->tags) == false) && $name !== '') {
- $newones[] = $name;
+ if(!$this->hasTag($name) && $name !== '') {
+ $newones[] = new Tag($this->user, $this->type, $name);
}
if(!is_null($id) ) {
// Insert $objectid, $categoryid pairs if not exist.
@@ -346,26 +405,26 @@ class Tags implements \OCP\ITags {
if(is_array($this->tags)) {
foreach($this->tags as $tag) {
try {
- \OCP\DB::insertIfNotExist(self::TAG_TABLE,
- array(
- 'uid' => $this->user,
- 'type' => $this->type,
- 'category' => $tag,
- ));
+ if (!$this->mapper->tagExists($tag)) {
+ $this->mapper->insert($tag);
+ }
} catch(\Exception $e) {
\OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(),
\OCP\Util::ERROR);
}
}
+
// reload tags to get the proper ids.
- $this->loadTags();
+ $this->tags = $this->mapper->loadTags($this->owners, $this->type);
+ \OCP\Util::writeLog('core', __METHOD__.', tags: ' . print_r($this->tags, true),
+ \OCP\Util::DEBUG);
// Loop through temporarily cached objectid/tagname pairs
// and save relations.
$tags = $this->tags;
// For some reason this is needed or array_search(i) will return 0..?
ksort($tags);
foreach(self::$relations as $relation) {
- $tagId = $this->array_searchi($relation['tag'], $tags);
+ $tagId = $this->getTagId($relation['tag']);
\OCP\Util::writeLog('core', __METHOD__ . 'catid, ' . $relation['tag'] . ' ' . $tagId, \OCP\Util::DEBUG);
if($tagId) {
try {
@@ -493,7 +552,7 @@ class Tags implements \OCP\ITags {
* @return boolean
*/
public function addToFavorites($objid) {
- if(!$this->hasTag(self::TAG_FAVORITE)) {
+ if(!$this->userHasTag(self::TAG_FAVORITE, $this->user)) {
$this->add(self::TAG_FAVORITE);
}
return $this->tagAs($objid, self::TAG_FAVORITE);
@@ -526,7 +585,7 @@ class Tags implements \OCP\ITags {
if(!$this->hasTag($tag)) {
$this->add($tag);
}
- $tagId = $this->array_searchi($tag, $this->tags);
+ $tagId = $this->getTagId($tag);
} else {
$tagId = $tag;
}
@@ -559,7 +618,7 @@ class Tags implements \OCP\ITags {
\OCP\Util::writeLog('core', __METHOD__.', Tag name is empty', \OCP\Util::DEBUG);
return false;
}
- $tagId = $this->array_searchi($tag, $this->tags);
+ $tagId = $this->getTagId($tag);
} else {
$tagId = $tag;
}
@@ -578,9 +637,9 @@ class Tags implements \OCP\ITags {
}
/**
- * Delete tags from the
+ * Delete tags from the database.
*
- * @param string[] $names An array of tags to delete
+ * @param string[]|integer[] $names An array of tags (names or IDs) to delete
* @return bool Returns false on error
*/
public function delete($names) {
@@ -596,21 +655,19 @@ class Tags implements \OCP\ITags {
foreach($names as $name) {
$id = null;
- if($this->hasTag($name)) {
- $id = $this->array_searchi($name, $this->tags);
- unset($this->tags[$id]);
+ if (is_numeric($name)) {
+ $key = $this->getTagById($name);
+ } else {
+ $key = $this->getTagByName($name);
}
- try {
- $stmt = \OCP\DB::prepare('DELETE FROM `' . self::TAG_TABLE . '` WHERE '
- . '`uid` = ? AND `type` = ? AND `category` = ?');
- $result = $stmt->execute(array($this->user, $this->type, $name));
- if (\OCP\DB::isError($result)) {
- \OCP\Util::writeLog('core', __METHOD__. 'DB error: ' . \OCP\DB::getErrorMessage($result), \OCP\Util::ERROR);
- }
- } catch(\Exception $e) {
- \OCP\Util::writeLog('core', __METHOD__ . ', exception: '
- . $e->getMessage(), \OCP\Util::ERROR);
- return false;
+ if ($key !== false) {
+ $tag = $this->tags[$key];
+ $id = $tag->getId();
+ unset($this->tags[$key]);
+ $this->mapper->delete($tag);
+ } else {
+ \OCP\Util::writeLog('core', __METHOD__ . 'Cannot delete tag ' . $name
+ . ': not found.', \OCP\Util::ERROR);
}
if(!is_null($id) && $id !== false) {
try {
@@ -634,19 +691,67 @@ class Tags implements \OCP\ITags {
return true;
}
- // case-insensitive in_array
- private function in_arrayi($needle, $haystack) {
+ // case-insensitive array_search
+ protected function array_searchi($needle, $haystack, $mem='getName') {
if(!is_array($haystack)) {
return false;
}
- return in_array(strtolower($needle), array_map('strtolower', $haystack));
+ return array_search(strtolower($needle), array_map(
+ function($tag) use($mem) {
+ return strtolower(call_user_func(array($tag, $mem)));
+ }, $haystack)
+ );
}
- // case-insensitive array_search
- private function array_searchi($needle, $haystack) {
- if(!is_array($haystack)) {
- return false;
+ /**
+ * Get a tag's ID.
+ *
+ * @param string $name The tag name to look for.
+ * @return string|bool The tag's id or false if no matching tag is found.
+ */
+ private function getTagId($name) {
+ $key = $this->array_searchi($name, $this->tags);
+ if ($key !== false) {
+ return $this->tags[$key]->getId();
}
- return array_search(strtolower($needle), array_map('strtolower', $haystack));
+ return false;
+ }
+
+ /**
+ * Get a tag by its name.
+ *
+ * @param string $name The tag name.
+ * @return integer|bool The tag object's offset within the $this->tags
+ * array or false if it doesn't exist.
+ */
+ private function getTagByName($name) {
+ return $this->array_searchi($name, $this->tags, 'getName');
+ }
+
+ /**
+ * Get a tag by its ID.
+ *
+ * @param string $id The tag ID to look for.
+ * @return integer|bool The tag object's offset within the $this->tags
+ * array or false if it doesn't exist.
+ */
+ private function getTagById($id) {
+ return $this->array_searchi($id, $this->tags, 'getId');
+ }
+
+ /**
+ * Returns an array mapping a given tag's properties to its values:
+ * ['id' => 0, 'name' = 'Tag', 'owner' = 'User', 'type' => 'tagtype']
+ *
+ * @param Tag $tag The tag that is going to be mapped
+ * @return array
+ */
+ private function tagMap(Tag $tag) {
+ return array(
+ 'id' => $tag->getId(),
+ 'name' => $tag->getName(),
+ 'owner' => $tag->getOwner(),
+ 'type' => $tag->getType()
+ );
}
}
diff --git a/lib/public/itagmanager.php b/lib/public/itagmanager.php
index 40487de42b4..54daa5cc1cb 100644
--- a/lib/public/itagmanager.php
+++ b/lib/public/itagmanager.php
@@ -48,8 +48,9 @@ interface ITagManager {
* @see \OCP\ITags
* @param string $type The type identifier e.g. 'contact' or 'event'.
* @param array $defaultTags An array of default tags to be used if none are stored.
+ * @param boolean $includeShared Whether to include tags for items shared with this user by others.
* @return \OCP\ITags
*/
- public function load($type, $defaultTags=array());
+ public function load($type, $defaultTags=array(), $includeShared=false);
-} \ No newline at end of file
+}
diff --git a/lib/public/itags.php b/lib/public/itags.php
index 1cba07e9b53..4514746bbe8 100644
--- a/lib/public/itags.php
+++ b/lib/public/itags.php
@@ -54,6 +54,15 @@ interface ITags {
public function isEmpty();
/**
+ * Returns an array mapping a given tag's properties to its values:
+ * ['id' => 0, 'name' = 'Tag', 'owner' = 'User', 'type' => 'tagtype']
+ *
+ * @param string $id The ID of the tag that is going to be mapped
+ * @return array|false
+ */
+ public function getTag($id);
+
+ /**
* Get the tags for a specific user.
*
* This returns an array with id/name maps:
@@ -85,6 +94,16 @@ interface ITags {
public function hasTag($name);
/**
+ * Checks whether a tag is saved for the given user,
+ * disregarding the ones shared with him or her.
+ *
+ * @param string $name The tag name to check for.
+ * @param string $user The user whose tags are to be checked.
+ * @return bool
+ */
+ public function userHasTag($name, $user);
+
+ /**
* Add a new tag.
*
* @param string $name A string with a name of the tag
@@ -95,7 +114,7 @@ interface ITags {
/**
* Rename tag.
*
- * @param string $from The name of the existing tag
+ * @param string|integer $from The name or ID of the existing tag
* @param string $to The new name of the tag.
* @return bool
*/
@@ -162,11 +181,11 @@ interface ITags {
public function unTag($objid, $tag);
/**
- * Delete tags from the
+ * Delete tags from the database
*
- * @param string[] $names An array of tags to delete
+ * @param string[]|integer[] $names An array of tags (names or IDs) to delete
* @return bool Returns false on error
*/
public function delete($names);
-} \ No newline at end of file
+}
diff --git a/tests/lib/share/backend.php b/tests/lib/share/backend.php
index 50ce24e07b6..61b8f262a42 100644
--- a/tests/lib/share/backend.php
+++ b/tests/lib/share/backend.php
@@ -29,9 +29,10 @@ class Test_Share_Backend implements OCP\Share_Backend {
private $testItem1 = 'test.txt';
private $testItem2 = 'share.txt';
+ private $testId = 1;
public function isValidSource($itemSource, $uidOwner) {
- if ($itemSource == $this->testItem1 || $itemSource == $this->testItem2) {
+ if ($itemSource == $this->testItem1 || $itemSource == $this->testItem2 || $itemSource == 1) {
return true;
}
}
diff --git a/tests/lib/tags.php b/tests/lib/tags.php
index 976b4b4fdc8..2f7a1e817f8 100644
--- a/tests/lib/tags.php
+++ b/tests/lib/tags.php
@@ -34,7 +34,8 @@ class Test_Tags extends PHPUnit_Framework_TestCase {
$this->objectType = uniqid('type_');
OC_User::createUser($this->user, 'pass');
OC_User::setUserId($this->user);
- $this->tagMgr = new OC\TagManager($this->user);
+ $this->tagMapper = new OC\Tagging\TagMapper(new OC\AppFramework\Db\Db());
+ $this->tagMgr = new OC\TagManager($this->tagMapper, $this->user);
}
@@ -84,7 +85,36 @@ class Test_Tags extends PHPUnit_Framework_TestCase {
$this->assertTrue($tagger->hasTag($tag));
}
- $this->assertCount(4, $tagger->getTags(), 'Not all tags added');
+ $tagMaps = $tagger->getTags();
+ $this->assertCount(4, $tagMaps, 'Not all tags added');
+ foreach($tagMaps as $tagMap) {
+ $this->assertEquals(null, $tagMap['id']);
+ }
+
+ // As addMultiple has been called without $sync=true, the tags aren't
+ // saved to the database, so they're gone when we reload $tagger:
+
+ $tagger = $this->tagMgr->load($this->objectType);
+ $this->assertEquals(0, count($tagger->getTags()));
+
+ // Now, we call addMultiple() with $sync=true so the tags will be
+ // be saved to the database.
+ $result = $tagger->addMultiple($tags, true);
+ $this->assertTrue((bool)$result);
+
+ $tagMaps = $tagger->getTags();
+ foreach($tagMaps as $tagMap) {
+ $this->assertNotEquals(null, $tagMap['id']);
+ }
+
+ // Reload the tagger.
+ $tagger = $this->tagMgr->load($this->objectType);
+
+ foreach($tags as $tag) {
+ $this->assertTrue($tagger->hasTag($tag));
+ }
+
+ $this->assertCount(4, $tagger->getTags(), 'Not all previously saved tags found');
}
public function testIsEmpty() {
@@ -120,8 +150,8 @@ class Test_Tags extends PHPUnit_Framework_TestCase {
$this->assertTrue($tagger->rename('Wrok', 'Work'));
$this->assertTrue($tagger->hasTag('Work'));
$this->assertFalse($tagger->hastag('Wrok'));
- $this->assertFalse($tagger->rename('Wrok', 'Work'));
-
+ $this->assertFalse($tagger->rename('Wrok', 'Work')); // Rename non-existant tag.
+ $this->assertFalse($tagger->rename('Work', 'Family')); // Collide with existing tag.
}
public function testTagAs() {
@@ -160,7 +190,33 @@ class Test_Tags extends PHPUnit_Framework_TestCase {
public function testFavorite() {
$tagger = $this->tagMgr->load($this->objectType);
$this->assertTrue($tagger->addToFavorites(1));
+ $this->assertEquals(array(1), $tagger->getFavorites());
$this->assertTrue($tagger->removeFromFavorites(1));
+ $this->assertEquals(array(), $tagger->getFavorites());
+ }
+
+ public function testShareTags() {
+ $test_tag = 'TestTag';
+ OCP\Share::registerBackend('test', 'Test_Share_Backend');
+
+ $tagger = $this->tagMgr->load('test');
+ $tagger->tagAs(1, $test_tag);
+
+ $other_user = uniqid('user2_');
+ OC_User::createUser($other_user, 'pass');
+
+ OC_User::setUserId($other_user);
+ $other_tagMgr = new OC\TagManager($this->tagMapper, $other_user);
+ $other_tagger = $other_tagMgr->load('test');
+ $this->assertFalse($other_tagger->hasTag($test_tag));
+
+ OC_User::setUserId($this->user);
+ OCP\Share::shareItem('test', 1, OCP\Share::SHARE_TYPE_USER, $other_user, OCP\PERMISSION_READ);
+
+ OC_User::setUserId($other_user);
+ $other_tagger = $other_tagMgr->load('test', array(), true); // Update tags, load shared ones.
+ $this->assertTrue($other_tagger->hasTag($test_tag));
+ $this->assertContains(1, $other_tagger->getIdsForTag($test_tag));
}
}