From 1dbe240b0e5b0a0b32d0e0eca596bf4e510f980e Mon Sep 17 00:00:00 2001 From: Vincent Petry Date: Tue, 7 Jul 2015 17:29:54 +0200 Subject: [PATCH] Disable app that bricks the server after enabling If an app is getting enabled in the web UI, an ajax call is now made to make sure the server still works. If it doesn't, it sends an emergency app disabling call to disable the breaking app. --- lib/base.php | 20 +++++++++- settings/js/apps.js | 90 +++++++++++++++++++++++++++++++-------------- 2 files changed, 80 insertions(+), 30 deletions(-) diff --git a/lib/base.php b/lib/base.php index df4e91dda9..31d9666698 100644 --- a/lib/base.php +++ b/lib/base.php @@ -823,12 +823,28 @@ class OC { exit(); } - $request = \OC::$server->getRequest()->getPathInfo(); - if (substr($request, -3) !== '.js') { // we need these files during the upgrade + $request = \OC::$server->getRequest(); + $requestPath = $request->getPathInfo(); + if (substr($requestPath, -3) !== '.js') { // we need these files during the upgrade self::checkMaintenanceMode(); self::checkUpgrade(); } + // emergency app disabling + if ($requestPath === '/disableapp' + && $request->getMethod() === 'POST' + && ((string)$request->getParam('appid')) !== '' + ) { + \OCP\JSON::callCheck(); + \OCP\JSON::checkAdminUser(); + $appId = (string)$request->getParam('appid'); + $appId = \OC_App::cleanAppId($appId); + + \OC_App::disable($appId); + \OC_JSON::success(); + exit(); + } + // Always load authentication apps OC_App::loadApps(['authentication']); diff --git a/settings/js/apps.js b/settings/js/apps.js index a99df65e3c..e6631762fd 100644 --- a/settings/js/apps.js +++ b/settings/js/apps.js @@ -4,7 +4,7 @@ Handlebars.registerHelper('score', function() { if(this.score) { var score = Math.round( this.score / 10 ); var imageName = 'rating/s' + score + '.png'; - + return new Handlebars.SafeString(''); } return new Handlebars.SafeString(''); @@ -212,7 +212,19 @@ OC.Settings.Apps = OC.Settings.Apps || { return app.types && app.types.indexOf(type) !== -1; }, + /** + * Checks the server health. + * + * If the promise fails, the server is broken. + * + * @return {Promise} promise + */ + _checkServerHealth: function() { + return $.get(OC.generateUrl('apps/files')); + }, + enableApp:function(appId, active, element, groups) { + var self = this; OC.Settings.Apps.hideErrorMessage(appId); groups = groups || []; var appItem = $('div#app-'+appId+''); @@ -242,6 +254,8 @@ OC.Settings.Apps = OC.Settings.Apps || { } },'json'); } else { + // TODO: display message to admin to not refresh the page! + // TODO: lock UI to prevent further operations $.post(OC.filePath('settings','ajax','enableapp.php'),{appid: appId, groups: groups},function(result) { if(!result || result.status !== 'success') { if (result.data && result.data.message) { @@ -254,35 +268,55 @@ OC.Settings.Apps = OC.Settings.Apps || { element.val(t('settings','Enable')); appItem.addClass('appwarning'); } else { - if (result.data.update_required) { - OC.Settings.Apps.showReloadMessage(); + self._checkServerHealth().done(function() { + if (result.data.update_required) { + OC.Settings.Apps.showReloadMessage(); - setTimeout(function() { - location.reload(); - }, 5000); - } - - OC.Settings.Apps.rebuildNavigation(); - appItem.data('active',true); - element.data('active',true); - appItem.addClass('active'); - element.val(t('settings','Disable')); - var app = OC.Settings.Apps.State.apps[appId]; - app.active = true; - - if (OC.Settings.Apps.isType(app, 'filesystem') || OC.Settings.Apps.isType(app, 'prelogin') || - OC.Settings.Apps.isType(app, 'authentication') || OC.Settings.Apps.isType(app, 'logging')) { - element.parent().find(".groups-enable").attr('checked', null); - element.parent().find(".groups-enable").hide(); - element.parent().find('#group_select').hide().val(null); - } else { - element.parent().find("#groups-enable").show(); - if (groups) { - appItem.data('groups', JSON.stringify(groups)); - } else { - appItem.data('groups', ''); + setTimeout(function() { + location.reload(); + }, 5000); } - } + + OC.Settings.Apps.rebuildNavigation(); + appItem.data('active',true); + element.data('active',true); + appItem.addClass('active'); + element.val(t('settings','Disable')); + var app = OC.Settings.Apps.State.apps[appId]; + app.active = true; + + if (OC.Settings.Apps.isType(app, 'filesystem') || OC.Settings.Apps.isType(app, 'prelogin') || + OC.Settings.Apps.isType(app, 'authentication') || OC.Settings.Apps.isType(app, 'logging')) { + element.parent().find(".groups-enable").attr('checked', null); + element.parent().find(".groups-enable").hide(); + element.parent().find('#group_select').hide().val(null); + } else { + element.parent().find("#groups-enable").show(); + if (groups) { + appItem.data('groups', JSON.stringify(groups)); + } else { + appItem.data('groups', ''); + } + } + }).fail(function() { + // server borked, emergency disable app + $.post(OC.webroot + '/index.php/disableapp', {appid: appId}, function() { + OC.Settings.Apps.showErrorMessage( + appId, + t('settings', 'Error: this app cannot be enabled because it makes the server unstable') + ); + appItem.data('errormsg', t('settings', 'Error while enabling app')); + element.val(t('settings','Enable')); + appItem.addClass('appwarning'); + }).fail(function() { + OC.Settings.Apps.showErrorMessage( + appId, + t('settings', 'Error: could not disable broken app') + ); + appItem.data('errormsg', t('settings', 'Error while disabling broken app')); + element.val(t('settings','Enable')); + }); + }); } },'json') .fail(function() {