diff --git a/application/Espo/Controllers/Extension.php b/application/Espo/Controllers/Extension.php new file mode 100644 index 0000000000..288b39d615 --- /dev/null +++ b/application/Espo/Controllers/Extension.php @@ -0,0 +1,82 @@ +getUser()->isAdmin()) { + throw new Forbidden(); + } + } + + public function actionCreate() + { + throw new Forbidden(); + } + + public function actionUpdate() + { + throw new Forbidden(); + } + + public function actionPatch() + { + throw new Forbidden(); + } + + public function actionListLinked() + { + throw new Forbidden(); + } + + public function actionDelete() + { + throw new Forbidden(); + } + + public function actionMassUpdate() + { + throw new Forbidden(); + } + + public function actionMassDelete() + { + throw new Forbidden(); + } + + public function actionCreateLink() + { + throw new Forbidden(); + } + + public function actionRemoveLink() + { + throw new Forbidden(); + } +} + diff --git a/application/Espo/Entities/Extension.php b/application/Espo/Entities/Extension.php new file mode 100644 index 0000000000..abad6e82e9 --- /dev/null +++ b/application/Espo/Entities/Extension.php @@ -0,0 +1,29 @@ +here.", - "selectLayout": "Select needed layout in the left menu and edit it." + "selectLayout": "Select needed layout in the left menu and edit it.", + "selectExtensionPackage": "Select extension package" }, "descriptions": { "settings": "System settings of application.", @@ -117,7 +122,8 @@ "userInterface": "Configure UI.", "authTokens": "Active auth sessions. IP address and last access date.", "authentication": "Authentication settings.", - "currency": "Currency settings and rates." + "currency": "Currency settings and rates.", + "extensions": "Install or uninstall extensions." }, "options": { "previewSize": { diff --git a/application/Espo/Resources/i18n/en_US/Global.json b/application/Espo/Resources/i18n/en_US/Global.json index 6b1187c9e7..b9879cf8b8 100644 --- a/application/Espo/Resources/i18n/en_US/Global.json +++ b/application/Espo/Resources/i18n/en_US/Global.json @@ -8,7 +8,8 @@ "EmailAccount": "Email Account", "OutboundEmail": "Outbound Email", "ScheduledJob": "Scheduled Job", - "ExternalAccount": "External Account" + "ExternalAccount": "External Account", + "Extension": "Extension" }, "scopeNamesPlural": { "Email": "Emails", @@ -19,7 +20,8 @@ "EmailAccount": "Email Accounts", "OutboundEmail": "Outbound Emails", "ScheduledJob": "Scheduled Jobs", - "ExternalAccount": "External Accounts" + "ExternalAccount": "External Accounts", + "Extension": "Extensions" }, "labels": { "Misc": "Misc", diff --git a/application/Espo/Resources/metadata/app/adminPanel.json b/application/Espo/Resources/metadata/app/adminPanel.json index 678376f374..3214279871 100644 --- a/application/Espo/Resources/metadata/app/adminPanel.json +++ b/application/Espo/Resources/metadata/app/adminPanel.json @@ -111,6 +111,11 @@ "url":"#Admin/userInterface", "label":"User Interface", "description":"userInterface" + }, + { + "url":"#Admin/extensions", + "label":"Extensions", + "description":"extensions" } ] } diff --git a/application/Espo/Resources/metadata/entityDefs/Extension.json b/application/Espo/Resources/metadata/entityDefs/Extension.json new file mode 100644 index 0000000000..20bb6f1847 --- /dev/null +++ b/application/Espo/Resources/metadata/entityDefs/Extension.json @@ -0,0 +1,41 @@ +{ + "fields": { + "name": { + "type": "varchar", + "required": true + }, + "status": { + "type": "enum", + "options": ["Enabled", "Disabled"] + }, + "version": { + "type": "varchar", + "required": true, + "maxLength": 50 + }, + "fileList": { + "type": "jsonArray" + }, + "description": { + "type": "text" + }, + "createdAt": { + "type": "datetime", + "readOnly": true + }, + "createdBy": { + "type": "link", + "readOnly": true + } + }, + "links": { + "createdBy": { + "type": "belongsTo", + "entity": "User" + } + }, + "collection": { + "sortBy": "createdAt", + "asc": false + } +} diff --git a/application/Espo/Resources/metadata/scopes/Extension.json b/application/Espo/Resources/metadata/scopes/Extension.json new file mode 100644 index 0000000000..55066c1a9f --- /dev/null +++ b/application/Espo/Resources/metadata/scopes/Extension.json @@ -0,0 +1,7 @@ +{ + "entity": true, + "layouts": false, + "tab": false, + "acl": false, + "customizable": false +} diff --git a/frontend/client/res/templates/admin/extensions/index.tpl b/frontend/client/res/templates/admin/extensions/index.tpl new file mode 100644 index 0000000000..6c640163d9 --- /dev/null +++ b/frontend/client/res/templates/admin/extensions/index.tpl @@ -0,0 +1,19 @@ + + +
+
+

{{translate 'selectExtensionPackage' category='messages' scope='Admin'}}

+
+
+
+ +
+
+
+ +
+
+
+ +
{{{list}}}
+ diff --git a/frontend/client/src/controllers/admin.js b/frontend/client/src/controllers/admin.js index 28471db75c..960443dd6e 100644 --- a/frontend/client/src/controllers/admin.js +++ b/frontend/client/src/controllers/admin.js @@ -159,6 +159,10 @@ Espo.define('Controllers.Admin', 'Controller', function (Dep) { this.main('Admin.Integrations.Index', {integration: integration}); }, + extensions: function (options) { + this.main('Admin.Extensions.Index'); + }, + rebuild: function (options) { var master = this.get('master'); Espo.Ui.notify(master.translate('Please wait...')); diff --git a/frontend/client/src/views/admin/extensions/index.js b/frontend/client/src/views/admin/extensions/index.js new file mode 100644 index 0000000000..af673a99e4 --- /dev/null +++ b/frontend/client/src/views/admin/extensions/index.js @@ -0,0 +1,148 @@ +/************************************************************************ + * This file is part of EspoCRM. + * + * EspoCRM - Open Source CRM application. + * Copyright (C) 2014 Yuri Kuznetsov, Taras Machyshyn, Oleksiy Avramenko + * Website: http://www.espocrm.com + * + * EspoCRM is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * EspoCRM 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with EspoCRM. If not, see http://www.gnu.org/licenses/. + ************************************************************************/ + +Espo.define('Views.Admin.Extensions.Index', 'View', function (Dep) { + + return Dep.extend({ + + template: "admin.extensions.index", + + packageContents: null, + + events: { + 'change input[name="package"]': function (e) { + this.$el.find('button[data-action="upload"]').addClass('disabled'); + this.$el.find('.message-container').html(''); + var files = e.currentTarget.files; + if (files.length) { + this.selectFile(files[0]); + } + }, + 'click button[data-action="upload"]': function () { + this.upload(); + } + }, + + setup: function () { + this.getCollectionFactory().create('Extension', function (collection) { + this.collection = collection; + + collection.maxSize = this.getConfig().get('recordsPerPage'); + + this.wait(true); + this.listenToOnce(collection, 'sync', function () { + this.createView('list', 'Extension.Record.List', { + collection: collection, + el: this.options.el + ' > .list-container', + }); + this.wait(false); + }); + + collection.fetch(); + + }, this); + }, + + selectFile: function (file) { + var fileReader = new FileReader(); + fileReader.onload = function (e) { + this.packageContents = e.target.result; + this.$el.find('button[data-action="upload"]').removeClass('disabled'); + }.bind(this); + fileReader.readAsDataURL(file); + }, + + showError: function (msg) { + msg = this.translate(msg, 'errors', 'Admin'); + this.$el.find('.message-container').html(msg); + }, + + upload: function () { + this.$el.find('button[data-action="upload"]').addClass('disabled'); + this.notify('Uploading...'); + $.ajax({ + url: 'Extension/action/upload', + type: 'POST', + contentType: 'application/zip', + timeout: 0, + data: this.packageContents, + error: function (xhr, t, e) { + this.showError(xhr.getResponseHeader('X-Status-Reason')); + this.notify(false); + }.bind(this) + }).done(function (data) { + if (!data.id) { + this.showError(this.translate('Error occured')); + return; + } + this.notify(false); + this.createView('popup', 'Admin.Extensions.Ready', { + upgradeData: data + }, function (view) { + view.render(); + this.$el.find('button[data-action="upload"]').removeClass('disabled'); + + view.once('run', function () { + view.close(); + this.$el.find('.panel.upload').addClass('hidden'); + this.run(data.id, data.version); + }, this); + }.bind(this)); + }.bind(this)).error; + }, + + textNotification: function (text) { + this.$el.find('.notify-text').html(text); + }, + + run: function (id, version) { + var msg = this.translate('Installing...', 'labels', 'Admin'); + this.notify('Please wait...'); + this.textNotification(msg); + + $.ajax({ + url: 'Extension/action/install', + type: 'POST', + data: JSON.stringify({ + id: id + }), + error: function (xhr) { + var msg = xhr.getResponseHeader('X-Status-Reason'); + this.textNotification(this.translate('Error') + ': ' + msg); + }.bind(this) + }).done(function () { + var cache = this.getCache(); + if (cache) { + cache.clear(); + } + this.createView('popup', 'Admin.Extensions.Done', { + version: version + }, function (view) { + this.notify(false); + view.render(); + }.bind(this)); + }.bind(this)); + }, + + }); + +}); + diff --git a/frontend/client/src/views/extension/record/list.js b/frontend/client/src/views/extension/record/list.js new file mode 100644 index 0000000000..b27b071e1e --- /dev/null +++ b/frontend/client/src/views/extension/record/list.js @@ -0,0 +1,41 @@ +/************************************************************************ + * This file is part of EspoCRM. + * + * EspoCRM - Open Source CRM application. + * Copyright (C) 2014 Yuri Kuznetsov, Taras Machyshyn, Oleksiy Avramenko + * Website: http://www.espocrm.com + * + * EspoCRM is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * EspoCRM 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with EspoCRM. If not, see http://www.gnu.org/licenses/. + ************************************************************************/ + +Espo.define('Views.Extension.Record.List', 'Views.Record.List', function (Dep) { + + return Dep.extend({ + + checkboxes: false, + + removeAction: false, + + mergeAction: false, + + massUpdateAction: false, + + exportAction: false, + + allowQuickEdit: false, + + }); + +}); +