diff options
Diffstat (limited to 'apps/workflowengine/src')
-rw-r--r-- | apps/workflowengine/src/admin.js | 398 | ||||
-rw-r--r-- | apps/workflowengine/src/filemimetypeplugin.js | 72 | ||||
-rw-r--r-- | apps/workflowengine/src/filenameplugin.js | 78 | ||||
-rw-r--r-- | apps/workflowengine/src/filesizeplugin.js | 56 | ||||
-rw-r--r-- | apps/workflowengine/src/filesystemtagsplugin.js | 78 | ||||
-rw-r--r-- | apps/workflowengine/src/requestremoteaddressplugin.js | 83 | ||||
-rw-r--r-- | apps/workflowengine/src/requesttimeplugin.js | 196 | ||||
-rw-r--r-- | apps/workflowengine/src/requesturlplugin.js | 117 | ||||
-rw-r--r-- | apps/workflowengine/src/requestuseragentplugin.js | 119 | ||||
-rw-r--r-- | apps/workflowengine/src/templates.js | 109 | ||||
-rw-r--r-- | apps/workflowengine/src/templates/operation.handlebars | 45 | ||||
-rw-r--r-- | apps/workflowengine/src/templates/operations.handlebars | 2 | ||||
-rw-r--r-- | apps/workflowengine/src/usergroupmembershipplugin.js | 75 | ||||
-rw-r--r-- | apps/workflowengine/src/workflowengine.js | 13 |
14 files changed, 1441 insertions, 0 deletions
diff --git a/apps/workflowengine/src/admin.js b/apps/workflowengine/src/admin.js new file mode 100644 index 00000000000..d986c5a494a --- /dev/null +++ b/apps/workflowengine/src/admin.js @@ -0,0 +1,398 @@ +/** + * @copyright Copyright (c) 2016 Morris Jobke <hey@morrisjobke.de> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program 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 program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +(function() { + Handlebars.registerHelper('selectItem', function(currentValue, itemValue) { + if (currentValue === itemValue) { + return 'selected="selected"'; + } + + return ""; + }); + + Handlebars.registerHelper('getOperators', function(classname) { + var check = OCA.WorkflowEngine.getCheckByClass(classname); + if (!_.isUndefined(check)) { + return check['operators']; + } + return []; + }); + + OCA.WorkflowEngine = _.extend(OCA.WorkflowEngine || {}, { + availablePlugins: [], + availableChecks: [], + + getCheckByClass: function(className) { + var length = OCA.WorkflowEngine.availableChecks.length; + for (var i = 0; i < length; i++) { + if (OCA.WorkflowEngine.availableChecks[i]['class'] === className) { + return OCA.WorkflowEngine.availableChecks[i]; + } + } + return undefined; + } + }); + + /** + * 888b d888 888 888 + * 8888b d8888 888 888 + * 88888b.d88888 888 888 + * 888Y88888P888 .d88b. .d88888 .d88b. 888 .d8888b + * 888 Y888P 888 d88""88b d88" 888 d8P Y8b 888 88K + * 888 Y8P 888 888 888 888 888 88888888 888 "Y8888b. + * 888 " 888 Y88..88P Y88b 888 Y8b. 888 X88 + * 888 888 "Y88P" "Y88888 "Y8888 888 88888P' + */ + + /** + * @class OCA.WorkflowEngine.Operation + */ + OCA.WorkflowEngine.Operation = + OC.Backbone.Model.extend({ + defaults: { + 'class': 'OCA\\WorkflowEngine\\Operation', + 'name': '', + 'checks': [], + 'operation': '' + } + }); + + /** + * .d8888b. 888 888 888 d8b + * d88P Y88b 888 888 888 Y8P + * 888 888 888 888 888 + * 888 .d88b. 888 888 .d88b. .d8888b 888888 888 .d88b. 88888b. .d8888b + * 888 d88""88b 888 888 d8P Y8b d88P" 888 888 d88""88b 888 "88b 88K + * 888 888 888 888 888 888 88888888 888 888 888 888 888 888 888 "Y8888b. + * Y88b d88P Y88..88P 888 888 Y8b. Y88b. Y88b. 888 Y88..88P 888 888 X88 + * "Y8888P" "Y88P" 888 888 "Y8888 "Y8888P "Y888 888 "Y88P" 888 888 88888P' + */ + + /** + * @class OCA.WorkflowEngine.OperationsCollection + * + * collection for all configurated operations + */ + OCA.WorkflowEngine.OperationsCollection = + OC.Backbone.Collection.extend({ + model: OCA.WorkflowEngine.Operation, + url: OC.generateUrl('apps/workflowengine/operations') + }); + + /** + * 888 888 d8b + * 888 888 Y8P + * 888 888 + * Y88b d88P 888 .d88b. 888 888 888 .d8888b + * Y88b d88P 888 d8P Y8b 888 888 888 88K + * Y88o88P 888 88888888 888 888 888 "Y8888b. + * Y888P 888 Y8b. Y88b 888 d88P X88 + * Y8P 888 "Y8888 "Y8888888P" 88888P' + */ + + /** + * @class OCA.WorkflowEngine.OperationView + * + * this creates the view for a single operation + */ + OCA.WorkflowEngine.OperationView = + OC.Backbone.View.extend({ + templateId: '#operation-template', + events: { + 'change .check-class': 'checkChanged', + 'change .check-operator': 'checkChanged', + 'change .check-value': 'checkChanged', + 'change .operation-name': 'operationChanged', + 'change .operation-operation': 'operationChanged', + 'click .button-reset': 'reset', + 'click .button-save': 'save', + 'click .button-add': 'add', + 'click .button-delete': 'delete', + 'click .button-delete-check': 'deleteCheck' + }, + originalModel: null, + hasChanged: false, + message: '', + errorMessage: '', + saving: false, + groups: [], + template: function(vars) { + return OCA.WorkflowEngine.Templates['operation'](_.extend( + { + shortRuleDescTXT: t('workflowengine', 'Short rule description'), + addRuleTXT: t('workflowengine', 'Add rule'), + resetTXT: t('workflowengine', 'Reset'), + saveTXT: t('workflowengine', 'Save'), + savingTXT: t('workflowengine', 'Saving…') + }, + vars + )); + }, + initialize: function() { + // this creates a new copy of the object to definitely have a new reference and being able to reset the model + this.originalModel = JSON.parse(JSON.stringify(this.model)); + this.model.on('change', function() { + console.log('model changed'); + this.hasChanged = true; + this.render(); + }, this); + + if (this.model.get('id') === undefined) { + this.hasChanged = true; + } + var self = this; + $.ajax({ + url: OC.linkToOCS('cloud/groups', 2) + 'details', + dataType: 'json', + quietMillis: 100, + }).success(function(data) { + if (data.ocs.data.groups && data.ocs.data.groups.length > 0) { + + data.ocs.data.groups.forEach(function(group) { + self.groups.push({ id: group.id, displayname: group.displayname }); + }); + self.render(); + + } else { + OC.Notification.error(t('workflowengine', 'Group list is empty'), { type: 'error' }); + console.log(data); + } + }).error(function(data) { + OC.Notification.error(t('workflowengine', 'Unable to retrieve the group list'), { type: 'error' }); + console.log(data); + }); + }, + delete: function() { + if (OC.PasswordConfirmation.requiresPasswordConfirmation()) { + OC.PasswordConfirmation.requirePasswordConfirmation(_.bind(this.delete, this)); + return; + } + + this.model.destroy(); + this.remove(); + }, + reset: function() { + this.hasChanged = false; + // silent is need to not trigger the change event which resets the hasChanged attribute + this.model.set(this.originalModel, { silent: true }); + this.render(); + }, + save: function() { + if (OC.PasswordConfirmation.requiresPasswordConfirmation()) { + OC.PasswordConfirmation.requirePasswordConfirmation(_.bind(this.save, this)); + return; + } + + var success = function(model, response, options) { + this.saving = false; + this.originalModel = JSON.parse(JSON.stringify(this.model)); + + this.message = t('workflowengine', 'Saved'); + this.errorMessage = ''; + this.render(); + }; + var error = function(model, response, options) { + this.saving = false; + this.hasChanged = true; + + this.message = t('workflowengine', 'Saving failed:'); + this.errorMessage = response.responseText; + this.render(); + }; + this.hasChanged = false; + this.saving = true; + this.render(); + this.model.save(null, { success: success, error: error, context: this }); + }, + add: function() { + var checks = _.clone(this.model.get('checks')), + classname = OCA.WorkflowEngine.availableChecks[0]['class'], + operators = OCA.WorkflowEngine.availableChecks[0]['operators']; + + checks.push({ + 'class': classname, + 'operator': operators[0]['operator'], + 'value': '' + }); + this.model.set({ 'checks': checks }); + }, + checkChanged: function(event) { + var value = event.target.value, + id = $(event.target.parentElement).data('id'), + // this creates a new copy of the object to definitely have a new reference + checks = JSON.parse(JSON.stringify(this.model.get('checks'))), + key = null; + + for (var i = 0; i < event.target.classList.length; i++) { + var className = event.target.classList[i]; + if (className.substr(0, 'check-'.length) === 'check-') { + key = className.substr('check-'.length); + break; + } + } + + if (key === null) { + console.warn('checkChanged triggered but element doesn\'t have any "check-" class'); + return; + } + + if (!_.has(checks[id], key)) { + console.warn('key "' + key + '" is not available in check', check); + return; + } + + checks[id][key] = value; + // if the class is changed most likely also the operators have changed + // with this we set the operator to the first possible operator + if (key === 'class') { + var check = OCA.WorkflowEngine.getCheckByClass(value); + if (!_.isUndefined(check)) { + checks[id]['operator'] = check['operators'][0]['operator']; + checks[id]['value'] = ''; + } + } + // model change will trigger render + this.model.set({ 'checks': checks }); + }, + deleteCheck: function(event) { + console.log(arguments); + var id = $(event.target.parentElement).data('id'), + checks = JSON.parse(JSON.stringify(this.model.get('checks'))); + + // splice removes 1 element at index `id` + checks.splice(id, 1); + // model change will trigger render + this.model.set({ 'checks': checks }); + }, + operationChanged: function(event) { + var value = event.target.value, + key = null; + + for (var i = 0; i < event.target.classList.length; i++) { + var className = event.target.classList[i]; + if (className.substr(0, 'operation-'.length) === 'operation-') { + key = className.substr('operation-'.length); + break; + } + } + + if (key === null) { + console.warn('operationChanged triggered but element doesn\'t have any "operation-" class'); + return; + } + + if (key !== 'name' && key !== 'operation') { + console.warn('key "' + key + '" is no valid attribute'); + return; + } + + // model change will trigger render + this.model.set(key, value); + }, + render: function() { + this.$el.html(this.template({ + operation: this.model.toJSON(), + classes: OCA.WorkflowEngine.availableChecks, + hasChanged: this.hasChanged, + message: this.message, + errorMessage: this.errorMessage, + saving: this.saving + })); + + var checks = this.model.get('checks'); + _.each(this.$el.find('.check'), function(element) { + var $element = $(element), + id = $element.data('id'), + check = checks[id], + valueElement = $element.find('.check-value').first(); + var self = this; + + _.each(OCA.WorkflowEngine.availablePlugins, function(plugin) { + if (_.isFunction(plugin.render)) { + plugin.render(valueElement, check, self.groups); + } + }); + }, this); + + if (this.message !== '') { + // hide success messages after some time + _.delay(function(elements) { + $(elements).css('opacity', 0); + }, 7000, this.$el.find('.msg.success')); + this.message = ''; + } + + return this.$el; + } + }); + + /** + * @class OCA.WorkflowEngine.OperationsView + * + * this creates the view for configured operations + */ + OCA.WorkflowEngine.OperationsView = + OC.Backbone.View.extend({ + templateId: '#operations-template', + collection: null, + $el: null, + events: { + 'click .button-add-operation': 'add' + }, + template: function(vars) { + return OCA.WorkflowEngine.Templates['operations'](_.extend( + { + addRuleGroupTXT: t('workflowengine', 'Add rule group') + }, + vars + )); + }, + initialize: function(classname) { + if (!OCA.WorkflowEngine.availablePlugins.length) { + OCA.WorkflowEngine.availablePlugins = OC.Plugins.getPlugins('OCA.WorkflowEngine.CheckPlugins'); + _.each(OCA.WorkflowEngine.availablePlugins, function(plugin) { + if (_.isFunction(plugin.getCheck)) { + OCA.WorkflowEngine.availableChecks.push(plugin.getCheck(classname)); + } + }); + } + + this.collection.fetch({ + data: { + 'class': classname + } + }); + this.collection.once('sync', this.render, this); + }, + add: function() { + var operation = this.collection.create(); + this.renderOperation(operation); + }, + renderOperation: function(subView) { + var operationsElement = this.$el.find('.operations'); + operationsElement.append(subView.$el); + subView.render(); + }, + render: function() { + this.$el.html(this.template()); + this.collection.each(this.renderOperation, this); + } + }); +})(); diff --git a/apps/workflowengine/src/filemimetypeplugin.js b/apps/workflowengine/src/filemimetypeplugin.js new file mode 100644 index 00000000000..17c092d209f --- /dev/null +++ b/apps/workflowengine/src/filemimetypeplugin.js @@ -0,0 +1,72 @@ +/** + * @copyright Copyright (c) 2016 Joas Schilling <coding@schilljs.com> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program 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 program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +(function() { + + OCA.WorkflowEngine = OCA.WorkflowEngine || {}; + OCA.WorkflowEngine.Plugins = OCA.WorkflowEngine.Plugins || {}; + + OCA.WorkflowEngine.Plugins.FileMimeTypePlugin = { + getCheck: function() { + return { + 'class': 'OCA\\WorkflowEngine\\Check\\FileMimeType', + 'name': t('workflowengine', 'File MIME type'), + 'operators': [ + {'operator': 'is', 'name': t('workflowengine', 'is')}, + {'operator': '!is', 'name': t('workflowengine', 'is not')}, + {'operator': 'matches', 'name': t('workflowengine', 'matches')}, + {'operator': '!matches', 'name': t('workflowengine', 'does not match')} + ] + }; + }, + render: function(element, check) { + if (check['class'] !== 'OCA\\WorkflowEngine\\Check\\FileMimeType') { + return; + } + + var placeholder = 'text/plain'; + if (check['operator'] === 'matches' || check['operator'] === '!matches') { + placeholder = '/^text\\/(plain|html)$/i'; + + if (this._validateRegex(check['value'])) { + $(element).removeClass('invalid-input'); + } else { + $(element).addClass('invalid-input'); + } + } + + $(element).css('width', '250px') + .attr('placeholder', placeholder) + .attr('title', t('workflowengine', 'Example: {placeholder}', {placeholder: placeholder})) + .addClass('has-tooltip') + .tooltip({ + placement: 'bottom' + }); + }, + + _validateRegex: function(string) { + var regexRegex = /^\/(.*)\/([gui]{0,3})$/, + result = regexRegex.exec(string); + return result !== null; + } + }; +})(); + +OC.Plugins.register('OCA.WorkflowEngine.CheckPlugins', OCA.WorkflowEngine.Plugins.FileMimeTypePlugin); diff --git a/apps/workflowengine/src/filenameplugin.js b/apps/workflowengine/src/filenameplugin.js new file mode 100644 index 00000000000..7d8018c29cd --- /dev/null +++ b/apps/workflowengine/src/filenameplugin.js @@ -0,0 +1,78 @@ +/** + * @copyright Copyright (c) 2018 Daniel Kesselberg <mail@danielkesselberg.de> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program 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 program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +(function () { + + OCA.WorkflowEngine = OCA.WorkflowEngine || {}; + OCA.WorkflowEngine.Plugins = OCA.WorkflowEngine.Plugins || {}; + + OCA.WorkflowEngine.Plugins.FileNamePlugin = { + getCheck: function () { + return { + 'class': 'OCA\\WorkflowEngine\\Check\\FileName', + 'name': t('workflowengine', 'File name'), + 'operators': [ + {'operator': 'is', 'name': t('workflowengine', 'is')}, + {'operator': '!is', 'name': t('workflowengine', 'is not')}, + { + 'operator': 'matches', + 'name': t('workflowengine', 'matches') + }, + { + 'operator': '!matches', + 'name': t('workflowengine', 'does not match') + } + ] + }; + }, + render: function (element, check) { + if (check['class'] !== 'OCA\\WorkflowEngine\\Check\\FileName') { + return; + } + + var placeholder = 'dummy.jpg'; + if (check['operator'] === 'matches' || check['operator'] === '!matches') { + placeholder = '/^dummy-.+$/i'; + + if (this._validateRegex(check['value'])) { + $(element).removeClass('invalid-input'); + } else { + $(element).addClass('invalid-input'); + } + } + + $(element).css('width', '250px') + .attr('placeholder', placeholder) + .attr('title', t('workflowengine', 'Example: {placeholder}', {placeholder: placeholder})) + .addClass('has-tooltip') + .tooltip({ + placement: 'bottom' + }); + }, + + _validateRegex: function (string) { + var regexRegex = /^\/(.*)\/([gui]{0,3})$/, + result = regexRegex.exec(string); + return result !== null; + } + }; +})(); + +OC.Plugins.register('OCA.WorkflowEngine.CheckPlugins', OCA.WorkflowEngine.Plugins.FileNamePlugin);
\ No newline at end of file diff --git a/apps/workflowengine/src/filesizeplugin.js b/apps/workflowengine/src/filesizeplugin.js new file mode 100644 index 00000000000..0efa9d00edf --- /dev/null +++ b/apps/workflowengine/src/filesizeplugin.js @@ -0,0 +1,56 @@ +/** + * @copyright Copyright (c) 2016 Joas Schilling <coding@schilljs.com> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program 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 program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +(function() { + + OCA.WorkflowEngine = OCA.WorkflowEngine || {}; + OCA.WorkflowEngine.Plugins = OCA.WorkflowEngine.Plugins || {}; + + OCA.WorkflowEngine.Plugins.FileSizePlugin = { + getCheck: function() { + return { + 'class': 'OCA\\WorkflowEngine\\Check\\FileSize', + 'name': t('workflowengine', 'File size (upload)'), + 'operators': [ + {'operator': 'less', 'name': t('workflowengine', 'less')}, + {'operator': '!greater', 'name': t('workflowengine', 'less or equals')}, + {'operator': '!less', 'name': t('workflowengine', 'greater or equals')}, + {'operator': 'greater', 'name': t('workflowengine', 'greater')} + ] + }; + }, + render: function(element, check) { + if (check['class'] !== 'OCA\\WorkflowEngine\\Check\\FileSize') { + return; + } + + var placeholder = '12 MB'; // Do not translate!!! + $(element).css('width', '250px') + .attr('placeholder', placeholder) + .attr('title', t('workflowengine', 'Example: {placeholder}', {placeholder: placeholder})) + .addClass('has-tooltip') + .tooltip({ + placement: 'bottom' + }); + } + }; +})(); + +OC.Plugins.register('OCA.WorkflowEngine.CheckPlugins', OCA.WorkflowEngine.Plugins.FileSizePlugin); diff --git a/apps/workflowengine/src/filesystemtagsplugin.js b/apps/workflowengine/src/filesystemtagsplugin.js new file mode 100644 index 00000000000..e66a35b73b9 --- /dev/null +++ b/apps/workflowengine/src/filesystemtagsplugin.js @@ -0,0 +1,78 @@ +/** + * @copyright Copyright (c) 2016 Joas Schilling <coding@schilljs.com> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program 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 program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +(function() { + + OCA.WorkflowEngine = OCA.WorkflowEngine || {}; + OCA.WorkflowEngine.Plugins = OCA.WorkflowEngine.Plugins || {}; + + OCA.WorkflowEngine.Plugins.FileSystemTagsPlugin = { + getCheck: function() { + this.collection = OC.SystemTags.collection; + + return { + 'class': 'OCA\\WorkflowEngine\\Check\\FileSystemTags', + 'name': t('workflowengine', 'File system tag'), + 'operators': [ + {'operator': 'is', 'name': t('workflowengine', 'is tagged with')}, + {'operator': '!is', 'name': t('workflowengine', 'is not tagged with')} + ] + }; + }, + render: function(element, check) { + if (check['class'] !== 'OCA\\WorkflowEngine\\Check\\FileSystemTags') { + return; + } + + $(element).css('width', '400px'); + + $(element).select2({ + allowClear: false, + multiple: false, + placeholder: t('workflowengine', 'Select tag…'), + query: _.debounce(function(query) { + query.callback({ + results: OC.SystemTags.collection.filterByName(query.term) + }); + }, 100, true), + id: function(element) { + return element.get('id'); + }, + initSelection: function(element, callback) { + callback($(element).val()); + }, + formatResult: function (tag) { + return OC.SystemTags.getDescriptiveTag(tag); + }, + formatSelection: function (tagId) { + var tag = OC.SystemTags.collection.get(tagId); + if (!_.isUndefined(tag)) { + return OC.SystemTags.getDescriptiveTag(tag); + } + }, + escapeMarkup: function(m) { + return m; + } + }); + } + }; +})(); + +OC.Plugins.register('OCA.WorkflowEngine.CheckPlugins', OCA.WorkflowEngine.Plugins.FileSystemTagsPlugin); diff --git a/apps/workflowengine/src/requestremoteaddressplugin.js b/apps/workflowengine/src/requestremoteaddressplugin.js new file mode 100644 index 00000000000..a66d6f51f0f --- /dev/null +++ b/apps/workflowengine/src/requestremoteaddressplugin.js @@ -0,0 +1,83 @@ +/** + * @copyright Copyright (c) 2016 Joas Schilling <coding@schilljs.com> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program 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 program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +(function() { + + OCA.WorkflowEngine = OCA.WorkflowEngine || {}; + OCA.WorkflowEngine.Plugins = OCA.WorkflowEngine.Plugins || {}; + + OCA.WorkflowEngine.Plugins.RequestRemoteAddressPlugin = { + getCheck: function() { + return { + 'class': 'OCA\\WorkflowEngine\\Check\\RequestRemoteAddress', + 'name': t('workflowengine', 'Request remote address'), + 'operators': [ + {'operator': 'matchesIPv4', 'name': t('workflowengine', 'matches IPv4')}, + {'operator': '!matchesIPv4', 'name': t('workflowengine', 'does not match IPv4')}, + {'operator': 'matchesIPv6', 'name': t('workflowengine', 'matches IPv6')}, + {'operator': '!matchesIPv6', 'name': t('workflowengine', 'does not match IPv6')} + ] + }; + }, + render: function(element, check) { + if (check['class'] !== 'OCA\\WorkflowEngine\\Check\\RequestRemoteAddress') { + return; + } + + var placeholder = '127.0.0.1/32'; // Do not translate!!! + if (check['operator'] === 'matchesIPv6' || check['operator'] === '!matchesIPv6') { + placeholder = '::1/128'; // Do not translate!!! + if (this._validateIPv6(check['value'])) { + $(element).removeClass('invalid-input'); + } else { + $(element).addClass('invalid-input'); + } + } else { + if (this._validateIPv4(check['value'])) { + $(element).removeClass('invalid-input'); + } else { + $(element).addClass('invalid-input'); + } + } + + $(element).css('width', '300px') + .attr('placeholder', placeholder) + .attr('title', t('workflowengine', 'Example: {placeholder}', {placeholder: placeholder})) + .addClass('has-tooltip') + .tooltip({ + placement: 'bottom' + }); + }, + + _validateIPv4: function(string) { + var regexRegex = /^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\/(3[0-2]|[1-2][0-9]|[1-9])$/, + result = regexRegex.exec(string); + return result !== null; + }, + + _validateIPv6: function(string) { + var regexRegex = /^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))\/(1([01][0-9]|2[0-8])|[1-9][0-9]|[0-9])$/, + result = regexRegex.exec(string); + return result !== null; + } + }; +})(); + +OC.Plugins.register('OCA.WorkflowEngine.CheckPlugins', OCA.WorkflowEngine.Plugins.RequestRemoteAddressPlugin); diff --git a/apps/workflowengine/src/requesttimeplugin.js b/apps/workflowengine/src/requesttimeplugin.js new file mode 100644 index 00000000000..111b2bb7437 --- /dev/null +++ b/apps/workflowengine/src/requesttimeplugin.js @@ -0,0 +1,196 @@ +/** + * @copyright Copyright (c) 2016 Joas Schilling <coding@schilljs.com> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program 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 program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +(function() { + + OCA.WorkflowEngine = OCA.WorkflowEngine || {}; + OCA.WorkflowEngine.Plugins = OCA.WorkflowEngine.Plugins || {}; + + OCA.WorkflowEngine.Plugins.RequestTimePlugin = { + timezones: [ + "Europe/Berlin", + "Europe/London" + ], + _$element: null, + getCheck: function() { + return { + 'class': 'OCA\\WorkflowEngine\\Check\\RequestTime', + 'name': t('workflowengine', 'Request time'), + 'operators': [ + {'operator': 'in', 'name': t('workflowengine', 'between')}, + {'operator': '!in', 'name': t('workflowengine', 'not between')} + ] + }; + }, + render: function(element, check) { + if (check['class'] !== 'OCA\\WorkflowEngine\\Check\\RequestTime') { + return; + } + + var startTime = '09:00', + endTime = '18:00', + timezone = jstz.determine().name(), + $element = $(element); + + if (_.isString(check['value']) && check['value'] !== '') { + var value = JSON.parse(check['value']), + splittedStart = value[0].split(' ', 2), + splittedEnd = value[1].split(' ', 2); + + startTime = splittedStart[0]; + endTime = splittedEnd[0]; + timezone = splittedStart[1]; + } + + var valueJSON = JSON.stringify([startTime + ' ' + timezone, endTime + ' ' + timezone]); + if (check['value'] !== valueJSON) { + check['value'] = valueJSON; + $element.val(valueJSON); + } + + $element.css('display', 'none'); + + $('<input>') + .attr('type', 'text') + .attr('placeholder', t('workflowengine', 'Start')) + .attr('title', t('workflowengine', 'Example: {placeholder}', {placeholder: '16:00'})) + .addClass('has-tooltip') + .tooltip({ + placement: 'bottom' + }) + .addClass('start') + .val(startTime) + .insertBefore($element); + $('<input>') + .attr('type', 'text') + .attr('placeholder', t('workflowengine', 'End')) + .attr('title', t('workflowengine', 'Example: {placeholder}', {placeholder: '16:00'})) + .addClass('has-tooltip') + .tooltip({ + placement: 'bottom' + }) + .addClass('end') + .val(endTime) + .insertBefore($element); + + var timezoneInput = $('<input>') + .attr('type', 'hidden') + .css('width', '250px') + .insertBefore($element) + .val(timezone); + + timezoneInput.select2({ + allowClear: false, + multiple: false, + placeholder: t('workflowengine', 'Select timezone…'), + ajax: { + url: OC.generateUrl('apps/workflowengine/timezones'), + dataType: 'json', + quietMillis: 100, + data: function (term) { + if (term === '') { + // Default search in the same continent... + term = jstz.determine().name().split('/'); + term = term[0]; + } + return { + search: term + }; + }, + results: function (response) { + var results = []; + $.each(response, function(timezone) { + results.push({ id: timezone }); + }); + + return { + results: results, + more: false + }; + } + }, + initSelection: function (element, callback) { + callback(element.val()); + }, + formatResult: function (element) { + return '<span>' + element.id + '</span>'; + }, + formatSelection: function (element) { + if (!_.isUndefined(element.id)) { + element = element.id; + } + return '<span>' + element + '</span>'; + } + }); + + // Has to be added after select2 for `event.target.classList` + timezoneInput.addClass('timezone'); + + $element.parent() + .on('change', '.start', _.bind(this.update, this)) + .on('change', '.end', _.bind(this.update, this)) + .on('change', '.timezone', _.bind(this.update, this)); + + this._$element = $element; + }, + update: function(event) { + var value = event.target.value, + key = null; + + for (var i = 0; i < event.target.classList.length; i++) { + key = event.target.classList[i]; + } + + if (key === null) { + console.warn('update triggered but element doesn\'t have any class'); + return; + } + + var data = JSON.parse(this._$element.val()), + startTime = moment(data[0].split(' ', 2)[0], 'H:m Z'), + endTime = moment(data[1].split(' ', 2)[0], 'H:m Z'), + timezone = data[0].split(' ', 2)[1]; + + if (key === 'start' || key === 'end') { + var parsedDate = moment(value, ['H:m', 'h:m a'], true).format('HH:mm'); + + if (parsedDate === 'Invalid date') { + return; + } + + var indexValue = 0; + if (key === 'end') { + indexValue = 1; + } + data[indexValue] = parsedDate + ' ' + timezone; + } + + if (key === 'timezone') { + data[0] = startTime.format('HH:mm') + ' ' + value; + data[1] = endTime.format('HH:mm') + ' ' + value; + } + + this._$element.val(JSON.stringify(data)); + this._$element.trigger('change'); + } + }; +})(); + +OC.Plugins.register('OCA.WorkflowEngine.CheckPlugins', OCA.WorkflowEngine.Plugins.RequestTimePlugin); diff --git a/apps/workflowengine/src/requesturlplugin.js b/apps/workflowengine/src/requesturlplugin.js new file mode 100644 index 00000000000..7c81deaaf33 --- /dev/null +++ b/apps/workflowengine/src/requesturlplugin.js @@ -0,0 +1,117 @@ +/** + * @copyright Copyright (c) 2016 Joas Schilling <coding@schilljs.com> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program 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 program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +(function() { + + OCA.WorkflowEngine = OCA.WorkflowEngine || {}; + OCA.WorkflowEngine.Plugins = OCA.WorkflowEngine.Plugins || {}; + + OCA.WorkflowEngine.Plugins.RequestURLPlugin = { + predefinedValues: ['webdav'], + getCheck: function() { + return { + 'class': 'OCA\\WorkflowEngine\\Check\\RequestURL', + 'name': t('workflowengine', 'Request URL'), + 'operators': [ + {'operator': 'is', 'name': t('workflowengine', 'is')}, + {'operator': '!is', 'name': t('workflowengine', 'is not')}, + {'operator': 'matches', 'name': t('workflowengine', 'matches')}, + {'operator': '!matches', 'name': t('workflowengine', 'does not match')} + ] + }; + }, + render: function(element, check) { + if (check['class'] !== 'OCA\\WorkflowEngine\\Check\\RequestURL') { + return; + } + + var placeholder = 'https://localhost/index.php'; + + if (check['operator'] === 'matches' || check['operator'] === '!matches') { + placeholder = '/^https\\:\\/\\/localhost\\/index\\.php$/i'; + } + + $(element).css('width', '250px') + .attr('placeholder', placeholder) + .attr('title', t('workflowengine', 'Example: {placeholder}', {placeholder: placeholder})) + .addClass('has-tooltip') + .tooltip({ + placement: 'bottom' + }); + + if (check['operator'] === 'matches' || check['operator'] === '!matches') { + if (this._validateRegex(check['value'])) { + $(element).removeClass('invalid-input'); + } else { + $(element).addClass('invalid-input'); + } + } else { + var self = this, + data = [ + { + text: t('workflowengine', 'Predefined URLs'), + children: [ + {id: 'webdav', text: t('workflowengine', 'Files WebDAV')} + ] + } + ]; + if (this.predefinedValues.indexOf(check['value']) === -1) { + data.unshift({ + id: check['value'], + text: check['value'] + }) + } + + + $(element).select2({ + data: data, + createSearchChoice: function(term) { + if (self.predefinedValues.indexOf(check['value']) === -1) { + return { + id: term, + text: term + }; + } + }, + id: function(element) { + return element.id; + }, + formatResult: function (tag) { + return tag.text; + }, + formatSelection: function (tag) { + return tag.text; + }, + escapeMarkup: function(m) { + return m; + } + }) + } + }, + + _validateRegex: function(string) { + var regexRegex = /^\/(.*)\/([gui]{0,3})$/, + result = regexRegex.exec(string); + return result !== null; + } + }; +})(); + +OC.Plugins.register('OCA.WorkflowEngine.CheckPlugins', OCA.WorkflowEngine.Plugins.RequestURLPlugin); diff --git a/apps/workflowengine/src/requestuseragentplugin.js b/apps/workflowengine/src/requestuseragentplugin.js new file mode 100644 index 00000000000..881ea4b8ac7 --- /dev/null +++ b/apps/workflowengine/src/requestuseragentplugin.js @@ -0,0 +1,119 @@ +/** + * @copyright Copyright (c) 2016 Joas Schilling <coding@schilljs.com> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program 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 program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +(function() { + + OCA.WorkflowEngine = OCA.WorkflowEngine || {}; + OCA.WorkflowEngine.Plugins = OCA.WorkflowEngine.Plugins || {}; + + OCA.WorkflowEngine.Plugins.RequestUserAgentPlugin = { + predefinedValues: ['android', 'ios', 'desktop'], + getCheck: function() { + return { + 'class': 'OCA\\WorkflowEngine\\Check\\RequestUserAgent', + 'name': t('workflowengine', 'Request user agent'), + 'operators': [ + {'operator': 'is', 'name': t('workflowengine', 'is')}, + {'operator': '!is', 'name': t('workflowengine', 'is not')}, + {'operator': 'matches', 'name': t('workflowengine', 'matches')}, + {'operator': '!matches', 'name': t('workflowengine', 'does not match')} + ] + }; + }, + render: function(element, check) { + if (check['class'] !== 'OCA\\WorkflowEngine\\Check\\RequestUserAgent') { + return; + } + + var placeholder = 'Mozilla/5.0 User Agent'; + + if (check.operator === 'matches' || check.operator === '!matches') { + placeholder = '/^Mozilla\\/5\\.0 (.*)$/i'; + } + + $(element).css('width', '250px') + .attr('placeholder', placeholder) + .attr('title', t('workflowengine', 'Example: {placeholder}', {placeholder: placeholder})) + .addClass('has-tooltip') + .tooltip({ + placement: 'bottom' + }); + + if (check.operator === 'matches' || check.operator === '!matches') { + if (this._validateRegex(check.value)) { + $(element).removeClass('invalid-input'); + } else { + $(element).addClass('invalid-input'); + } + } else { + var self = this, + data = [ + { + text: t('workflowengine', 'Sync clients'), + children: [ + {id: 'android', text: t('workflowengine', 'Android client')}, + {id: 'ios', text: t('workflowengine', 'iOS client')}, + {id: 'desktop', text: t('workflowengine', 'Desktop client')}, + {id: 'mail', text: t('workflowengine', 'Thunderbird & Outlook addons')} + ] + } + ]; + if (this.predefinedValues.indexOf(check.value) === -1) { + data.unshift({ + id: check.value, + text: check.value + }); + } + + $(element).select2({ + data: data, + createSearchChoice: function(term) { + if (self.predefinedValues.indexOf(check.value) === -1) { + return { + id: term, + text: term + }; + } + }, + id: function(element) { + return element.id; + }, + formatResult: function (tag) { + return tag.text; + }, + formatSelection: function (tag) { + return tag.text; + }, + escapeMarkup: function(m) { + return m; + } + }) + } + }, + + _validateRegex: function(string) { + var regexRegex = /^\/(.*)\/([gui]{0,3})$/, + result = regexRegex.exec(string); + return result !== null; + } + }; +})(); + +OC.Plugins.register('OCA.WorkflowEngine.CheckPlugins', OCA.WorkflowEngine.Plugins.RequestUserAgentPlugin); diff --git a/apps/workflowengine/src/templates.js b/apps/workflowengine/src/templates.js new file mode 100644 index 00000000000..157d396357d --- /dev/null +++ b/apps/workflowengine/src/templates.js @@ -0,0 +1,109 @@ +(function() { + var template = Handlebars.template, templates = OCA.WorkflowEngine.Templates = OCA.WorkflowEngine.Templates || {}; +templates['operation'] = template({"1":function(container,depth0,helpers,partials,data) { + return " modified"; +},"3":function(container,depth0,helpers,partials,data) { + return " <span class=\"button-delete icon-delete\"></span>\n"; +},"5":function(container,depth0,helpers,partials,data,blockParams,depths) { + var stack1, helper, alias1=depth0 != null ? depth0 : (container.nullContext || {}), alias2=helpers.helperMissing, alias3="function", alias4=container.escapeExpression; + + return " <div class=\"check\" data-id=\"" + + alias4(((helper = (helper = helpers.index || (data && data.index)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"index","hash":{},"data":data}) : helper))) + + "\">\n <select class=\"check-class\">\n" + + ((stack1 = helpers.each.call(alias1,(depths[1] != null ? depths[1].classes : depths[1]),{"name":"each","hash":{},"fn":container.program(6, data, 0, blockParams, depths),"inverse":container.noop,"data":data})) != null ? stack1 : "") + + " </select>\n <select class=\"check-operator\">\n" + + ((stack1 = helpers.each.call(alias1,(helpers.getOperators || (depth0 && depth0.getOperators) || alias2).call(alias1,(depth0 != null ? depth0["class"] : depth0),{"name":"getOperators","hash":{},"data":data}),{"name":"each","hash":{},"fn":container.program(8, data, 0, blockParams, depths),"inverse":container.noop,"data":data})) != null ? stack1 : "") + + " </select>\n <input type=\"text\" class=\"check-value\" value=\"" + + alias4(((helper = (helper = helpers.value || (depth0 != null ? depth0.value : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"value","hash":{},"data":data}) : helper))) + + "\">\n <span class=\"button-delete-check icon-delete\"></span>\n </div>\n"; +},"6":function(container,depth0,helpers,partials,data,blockParams,depths) { + var stack1, helper, alias1=depth0 != null ? depth0 : (container.nullContext || {}), alias2=helpers.helperMissing, alias3="function", alias4=container.escapeExpression; + + return " <option value=\"" + + alias4(((helper = (helper = helpers["class"] || (depth0 != null ? depth0["class"] : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"class","hash":{},"data":data}) : helper))) + + "\" " + + ((stack1 = (helpers.selectItem || (depth0 && depth0.selectItem) || alias2).call(alias1,(depth0 != null ? depth0["class"] : depth0),(depths[1] != null ? depths[1]["class"] : depths[1]),{"name":"selectItem","hash":{},"data":data})) != null ? stack1 : "") + + ">" + + alias4(((helper = (helper = helpers.name || (depth0 != null ? depth0.name : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"name","hash":{},"data":data}) : helper))) + + "</option>\n"; +},"8":function(container,depth0,helpers,partials,data,blockParams,depths) { + var stack1, helper, alias1=depth0 != null ? depth0 : (container.nullContext || {}), alias2=helpers.helperMissing, alias3="function", alias4=container.escapeExpression; + + return " <option value=\"" + + alias4(((helper = (helper = helpers.operator || (depth0 != null ? depth0.operator : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"operator","hash":{},"data":data}) : helper))) + + "\" " + + ((stack1 = (helpers.selectItem || (depth0 && depth0.selectItem) || alias2).call(alias1,(depth0 != null ? depth0.operator : depth0),(depths[1] != null ? depths[1].operator : depths[1]),{"name":"selectItem","hash":{},"data":data})) != null ? stack1 : "") + + ">" + + alias4(((helper = (helper = helpers.name || (depth0 != null ? depth0.name : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"name","hash":{},"data":data}) : helper))) + + "</option>\n"; +},"10":function(container,depth0,helpers,partials,data) { + var stack1, helper, alias1=depth0 != null ? depth0 : (container.nullContext || {}); + + return ((stack1 = helpers["if"].call(alias1,((stack1 = (depth0 != null ? depth0.operation : depth0)) != null ? stack1.id : stack1),{"name":"if","hash":{},"fn":container.program(11, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "") + + " <button class=\"button-save pull-right\">" + + container.escapeExpression(((helper = (helper = helpers.saveTXT || (depth0 != null ? depth0.saveTXT : depth0)) != null ? helper : helpers.helperMissing),(typeof helper === "function" ? helper.call(alias1,{"name":"saveTXT","hash":{},"data":data}) : helper))) + + "</button>\n"; +},"11":function(container,depth0,helpers,partials,data) { + var helper; + + return " <button class=\"button-reset pull-right\">" + + container.escapeExpression(((helper = (helper = helpers.resetTXT || (depth0 != null ? depth0.resetTXT : depth0)) != null ? helper : helpers.helperMissing),(typeof helper === "function" ? helper.call(depth0 != null ? depth0 : (container.nullContext || {}),{"name":"resetTXT","hash":{},"data":data}) : helper))) + + "</button>\n"; +},"13":function(container,depth0,helpers,partials,data) { + var helper; + + return " <span class=\"icon-loading-small pull-right\"></span>\n <span class=\"pull-right\">" + + container.escapeExpression(((helper = (helper = helpers.savingTXT || (depth0 != null ? depth0.savingTXT : depth0)) != null ? helper : helpers.helperMissing),(typeof helper === "function" ? helper.call(depth0 != null ? depth0 : (container.nullContext || {}),{"name":"savingTXT","hash":{},"data":data}) : helper))) + + "</span>\n "; +},"15":function(container,depth0,helpers,partials,data) { + var stack1; + + return ((stack1 = helpers["if"].call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.message : depth0),{"name":"if","hash":{},"fn":container.program(16, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : ""); +},"16":function(container,depth0,helpers,partials,data) { + var stack1, helper, alias1=depth0 != null ? depth0 : (container.nullContext || {}); + + return "\n <span class=\"msg pull-right " + + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.errorMessage : depth0),{"name":"if","hash":{},"fn":container.program(17, data, 0),"inverse":container.program(19, data, 0),"data":data})) != null ? stack1 : "") + + "\">\n " + + container.escapeExpression(((helper = (helper = helpers.message || (depth0 != null ? depth0.message : depth0)) != null ? helper : helpers.helperMissing),(typeof helper === "function" ? helper.call(alias1,{"name":"message","hash":{},"data":data}) : helper))) + + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.errorMessage : depth0),{"name":"if","hash":{},"fn":container.program(21, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "") + + "\n </span>\n "; +},"17":function(container,depth0,helpers,partials,data) { + return "error"; +},"19":function(container,depth0,helpers,partials,data) { + return "success"; +},"21":function(container,depth0,helpers,partials,data) { + var helper; + + return " " + + container.escapeExpression(((helper = (helper = helpers.errorMessage || (depth0 != null ? depth0.errorMessage : depth0)) != null ? helper : helpers.helperMissing),(typeof helper === "function" ? helper.call(depth0 != null ? depth0 : (container.nullContext || {}),{"name":"errorMessage","hash":{},"data":data}) : helper))); +},"compiler":[7,">= 4.0.0"],"main":function(container,depth0,helpers,partials,data,blockParams,depths) { + var stack1, helper, alias1=depth0 != null ? depth0 : (container.nullContext || {}), alias2=helpers.helperMissing, alias3="function", alias4=container.escapeExpression, alias5=container.lambda; + + return "<div class=\"operation" + + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.hasChanged : depth0),{"name":"if","hash":{},"fn":container.program(1, data, 0, blockParams, depths),"inverse":container.noop,"data":data})) != null ? stack1 : "") + + "\">\n <div class=\"operation-header\">\n <input type=\"text\" class=\"operation-name\" placeholder=\"" + + alias4(((helper = (helper = helpers.shortRuleDescTXT || (depth0 != null ? depth0.shortRuleDescTXT : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"shortRuleDescTXT","hash":{},"data":data}) : helper))) + + "\" value=\"" + + alias4(alias5(((stack1 = (depth0 != null ? depth0.operation : depth0)) != null ? stack1.name : stack1), depth0)) + + "\" />\n <input type=\"text\" class=\"operation-operation\" value=\"" + + alias4(alias5(((stack1 = (depth0 != null ? depth0.operation : depth0)) != null ? stack1.operation : stack1), depth0)) + + "\" />\n" + + ((stack1 = helpers["if"].call(alias1,((stack1 = (depth0 != null ? depth0.operation : depth0)) != null ? stack1.id : stack1),{"name":"if","hash":{},"fn":container.program(3, data, 0, blockParams, depths),"inverse":container.noop,"data":data})) != null ? stack1 : "") + + " </div>\n\n <div class=\"checks\">\n" + + ((stack1 = helpers.each.call(alias1,((stack1 = (depth0 != null ? depth0.operation : depth0)) != null ? stack1.checks : stack1),{"name":"each","hash":{},"fn":container.program(5, data, 0, blockParams, depths),"inverse":container.noop,"data":data})) != null ? stack1 : "") + + " </div>\n <button class=\"button-add\">" + + alias4(((helper = (helper = helpers.addRuleTXT || (depth0 != null ? depth0.addRuleTXT : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"addRuleTXT","hash":{},"data":data}) : helper))) + + "</button>\n" + + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.hasChanged : depth0),{"name":"if","hash":{},"fn":container.program(10, data, 0, blockParams, depths),"inverse":container.noop,"data":data})) != null ? stack1 : "") + + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.saving : depth0),{"name":"if","hash":{},"fn":container.program(13, data, 0, blockParams, depths),"inverse":container.program(15, data, 0, blockParams, depths),"data":data})) != null ? stack1 : "") + + "\n</div>\n"; +},"useData":true,"useDepths":true}); +templates['operations'] = template({"compiler":[7,">= 4.0.0"],"main":function(container,depth0,helpers,partials,data) { + var helper; + + return "<div class=\"operations\"></div>\n<button class=\"button-add-operation\">" + + container.escapeExpression(((helper = (helper = helpers.addRuleGroupTXT || (depth0 != null ? depth0.addRuleGroupTXT : depth0)) != null ? helper : helpers.helperMissing),(typeof helper === "function" ? helper.call(depth0 != null ? depth0 : (container.nullContext || {}),{"name":"addRuleGroupTXT","hash":{},"data":data}) : helper))) + + "</button>\n"; +},"useData":true}); +})();
\ No newline at end of file diff --git a/apps/workflowengine/src/templates/operation.handlebars b/apps/workflowengine/src/templates/operation.handlebars new file mode 100644 index 00000000000..0899890cef2 --- /dev/null +++ b/apps/workflowengine/src/templates/operation.handlebars @@ -0,0 +1,45 @@ +<div class="operation{{#if hasChanged}} modified{{/if}}"> + <div class="operation-header"> + <input type="text" class="operation-name" placeholder="{{shortRuleDescTXT}}" value="{{operation.name}}" /> + <input type="text" class="operation-operation" value="{{operation.operation}}" /> + {{! delete only makes sense if the operation is already saved }} + {{#if operation.id}} + <span class="button-delete icon-delete"></span> + {{/if}} + </div> + + <div class="checks"> + {{#each operation.checks}} + <div class="check" data-id="{{@index}}"> + <select class="check-class"> + {{#each ../classes}} + <option value="{{class}}" {{{selectItem class ../class}}}>{{name}}</option> + {{/each}} + </select> + <select class="check-operator"> + {{#each (getOperators class)}} + <option value="{{operator}}" {{{selectItem operator ../operator}}}>{{name}}</option> + {{/each}} + </select> + <input type="text" class="check-value" value="{{value}}"> + <span class="button-delete-check icon-delete"></span> + </div> + {{/each}} + </div> + <button class="button-add">{{addRuleTXT}}</button> + {{#if hasChanged}} + {{! reset only makes sense if the operation is already saved }} + {{#if operation.id}} + <button class="button-reset pull-right">{{resetTXT}}</button> + {{/if}} + <button class="button-save pull-right">{{saveTXT}}</button> + {{/if}} + {{#if saving}} + <span class="icon-loading-small pull-right"></span> + <span class="pull-right">{{savingTXT}}</span> + {{else}}{{#if message}} + <span class="msg pull-right {{#if errorMessage}}error{{else}}success{{/if}}"> + {{message}}{{#if errorMessage}} {{errorMessage}}{{/if}} + </span> + {{/if}}{{/if}} +</div> diff --git a/apps/workflowengine/src/templates/operations.handlebars b/apps/workflowengine/src/templates/operations.handlebars new file mode 100644 index 00000000000..14b62ee79a6 --- /dev/null +++ b/apps/workflowengine/src/templates/operations.handlebars @@ -0,0 +1,2 @@ +<div class="operations"></div> +<button class="button-add-operation">{{addRuleGroupTXT}}</button> diff --git a/apps/workflowengine/src/usergroupmembershipplugin.js b/apps/workflowengine/src/usergroupmembershipplugin.js new file mode 100644 index 00000000000..53f35fedf2d --- /dev/null +++ b/apps/workflowengine/src/usergroupmembershipplugin.js @@ -0,0 +1,75 @@ +/** + * @copyright Copyright (c) 2016 Morris Jobke <hey@morrisjobke.de> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program 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 program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +(function() { + + OCA.WorkflowEngine = OCA.WorkflowEngine || {}; + OCA.WorkflowEngine.Plugins = OCA.WorkflowEngine.Plugins || {}; + + OCA.WorkflowEngine.Plugins.UserGroupMembershipPlugin = { + getCheck: function() { + return { + 'class': 'OCA\\WorkflowEngine\\Check\\UserGroupMembership', + 'name': t('workflowengine', 'User group membership'), + 'operators': [ + {'operator': 'is', 'name': t('workflowengine', 'is member of')}, + {'operator': '!is', 'name': t('workflowengine', 'is not member of')} + ] + }; + }, + render: function(element, check, groups) { + if (check['class'] !== 'OCA\\WorkflowEngine\\Check\\UserGroupMembership') { + return; + } + + $(element).css('width', '400px'); + + $(element).select2({ + data: { results: groups, text: 'displayname' }, + initSelection: function (element, callback) { + var groupId = element.val(); + if (groupId && groups.length > 0) { + callback({ + id: groupId, + displayname: groups.find(function (group) { + return group.id === groupId; + }).displayname + }); + } else if (groupId) { + callback({ + id: groupId, + displayname: groupId + }); + } else { + callback(); + } + }, + formatResult: function (element) { + return '<span>' + escapeHTML(element.displayname) + '</span>'; + }, + formatSelection: function (element) { + return '<span title="'+escapeHTML(element.id)+'">'+escapeHTML(element.displayname)+'</span>'; + } + }); + } + }; +})(); + +OC.Plugins.register('OCA.WorkflowEngine.CheckPlugins', OCA.WorkflowEngine.Plugins.UserGroupMembershipPlugin); diff --git a/apps/workflowengine/src/workflowengine.js b/apps/workflowengine/src/workflowengine.js new file mode 100644 index 00000000000..48d670d203c --- /dev/null +++ b/apps/workflowengine/src/workflowengine.js @@ -0,0 +1,13 @@ +import './admin' +import './templates' +import './filemimetypeplugin' +import './filenameplugin' +import './filesizeplugin' +import './filesystemtagsplugin' +import './requestremoteaddressplugin' +import './requesttimeplugin' +import './requesturlplugin' +import './requestuseragentplugin' +import './usergroupmembershipplugin' + +window.OCA.WorkflowEngine = OCA.WorkflowEngine |