You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
606 lines
17 KiB
606 lines
17 KiB
/** |
|
* 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 Nextcloud 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 |
|
* Nextcloud 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 Nextcloud. 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 Nextcloud. 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 Nextcloud 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 Nextcloud 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 Nextcloud server |
|
*/ |
|
requestConfigurationTest: function() { |
|
var url = OC.generateUrl('apps/user_ldap/ajax/testConfiguration.php'); |
|
var params = OC.buildQueryString({ldap_serverconfig_chooser: this.configID}); |
|
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; |
|
})();
|
|
|