From f579f2bd948ca73a1af720e19517af9bdde11748 Mon Sep 17 00:00:00 2001 From: Georg Ehrke Date: Sat, 20 Dec 2014 22:44:41 +0100 Subject: [PATCH] add Download logfile button to admin settings add logSettingsController add download logfile button move getEntries to LogSettingsController move set log level to logsettingscontroller.php add warning if logfile is bigger than 100MB add unit test for set log level fix typecasting, add new line at EoF show log and logfile download only if log_type is set to owncloud add unit test for getFilenameForDownload --- lib/private/log/owncloud.php | 9 +- .../http/datadownloadresponse.php | 42 ++++++ settings/admin.php | 13 +- settings/ajax/getlog.php | 21 --- settings/ajax/setloglevel.php | 13 -- settings/application.php | 10 ++ settings/controller/logsettingscontroller.php | 126 ++++++++++++++++++ settings/js/admin.js | 2 +- settings/js/log.js | 12 +- settings/routes.php | 9 +- settings/templates/admin.php | 12 +- .../controller/logsettingscontrollertest.php | 79 +++++++++++ 12 files changed, 297 insertions(+), 51 deletions(-) create mode 100644 lib/public/appframework/http/datadownloadresponse.php delete mode 100644 settings/ajax/getlog.php delete mode 100644 settings/ajax/setloglevel.php create mode 100644 settings/controller/logsettingscontroller.php create mode 100644 tests/settings/controller/logsettingscontrollertest.php diff --git a/lib/private/log/owncloud.php b/lib/private/log/owncloud.php index d257bd12d2..c8ae61032a 100644 --- a/lib/private/log/owncloud.php +++ b/lib/private/log/owncloud.php @@ -111,7 +111,7 @@ class OC_Log_Owncloud { $entriesCount = 0; $lines = 0; // Loop through each character of the file looking for new lines - while ($pos >= 0 && $entriesCount < $limit) { + while ($pos >= 0 && ($limit === null ||$entriesCount < $limit)) { fseek($handle, $pos); $ch = fgetc($handle); if ($ch == "\n" || $pos == 0) { @@ -141,4 +141,11 @@ class OC_Log_Owncloud { } return $entries; } + + /** + * @return string + */ + public static function getLogFilePath() { + return self::$logFile; + } } diff --git a/lib/public/appframework/http/datadownloadresponse.php b/lib/public/appframework/http/datadownloadresponse.php new file mode 100644 index 0000000000..326be927b2 --- /dev/null +++ b/lib/public/appframework/http/datadownloadresponse.php @@ -0,0 +1,42 @@ + + * + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ +namespace OCP\AppFramework\Http; + +class DataDownloadResponse extends DownloadResponse { + /** + * @var string + */ + private $data; + + /** + * Creates a response that prompts the user to download the text + * @param string $data text to be downloaded + * @param string $filename the name that the downloaded file should have + * @param string $contentType the mimetype that the downloaded file should have + */ + public function __construct($data, $filename, $contentType) { + $this->data = $data; + parent::__construct($filename, $contentType); + } + + /** + * @param string $data + */ + public function setData($data) { + $this->data = $data; + } + + /** + * @return string + */ + public function render() { + return $this->data; + } +} diff --git a/settings/admin.php b/settings/admin.php index 56484f25b2..24ab428b04 100644 --- a/settings/admin.php +++ b/settings/admin.php @@ -10,8 +10,14 @@ OC_App::setActiveNavigationEntry("admin"); $template = new OC_Template('settings', 'admin', 'user'); -$entries = OC_Log_Owncloud::getEntries(3); -$entriesRemaining = count(OC_Log_Owncloud::getEntries(4)) > 3; +$showLog = (\OC::$server->getConfig()->getSystemValue('log_type', 'owncloud') === 'owncloud'); +$numEntriesToLoad = 3; +$entries = OC_Log_Owncloud::getEntries($numEntriesToLoad + 1); +$entriesRemaining = count($entries) > $numEntriesToLoad; +$entries = array_slice($entries, 0, $numEntriesToLoad); +$logFilePath = OC_Log_Owncloud::getLogFilePath(); +$doesLogFileExist = file_exists($logFilePath); +$logFileSize = filesize($logFilePath); $config = \OC::$server->getConfig(); $appConfig = \OC::$server->getAppConfig(); @@ -31,6 +37,9 @@ $template->assign('mail_smtpname', $config->getSystemValue("mail_smtpname", '')) $template->assign('mail_smtppassword', $config->getSystemValue("mail_smtppassword", '')); $template->assign('entries', $entries); $template->assign('entriesremain', $entriesRemaining); +$template->assign('logFileSize', $logFileSize); +$template->assign('doesLogFileExist', $doesLogFileExist); +$template->assign('showLog', $showLog); $template->assign('readOnlyConfigEnabled', OC_Helper::isReadOnlyConfigEnabled()); $template->assign('isLocaleWorking', OC_Util::isSetLocaleWorking()); $template->assign('isPhpCharSetUtf8', OC_Util::isPhpCharSetUtf8()); diff --git a/settings/ajax/getlog.php b/settings/ajax/getlog.php deleted file mode 100644 index 34c8d3ce46..0000000000 --- a/settings/ajax/getlog.php +++ /dev/null @@ -1,21 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or later. - * See the COPYING-README file. - */ - -OC_JSON::checkAdminUser(); - -$count=(isset($_GET['count']))?$_GET['count']:50; -$offset=(isset($_GET['offset']))?$_GET['offset']:0; - -$entries=OC_Log_Owncloud::getEntries($count, $offset); -$data = array(); - -OC_JSON::success( - array( - "data" => $entries, - "remain" => count(OC_Log_Owncloud::getEntries(1, $offset + $count)) !== 0, - ) -); diff --git a/settings/ajax/setloglevel.php b/settings/ajax/setloglevel.php deleted file mode 100644 index 542219f86c..0000000000 --- a/settings/ajax/setloglevel.php +++ /dev/null @@ -1,13 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or later. - * See the COPYING-README file. - */ - -OC_Util::checkAdminUser(); -OCP\JSON::callCheck(); - -OC_Config::setValue( 'loglevel', $_POST['level'] ); - -echo 'true'; diff --git a/settings/application.php b/settings/application.php index 74d021c5bf..070da8024b 100644 --- a/settings/application.php +++ b/settings/application.php @@ -12,6 +12,7 @@ namespace OC\Settings; use OC\Settings\Controller\AppSettingsController; use OC\Settings\Controller\GroupsController; +use OC\Settings\Controller\LogSettingsController; use OC\Settings\Controller\MailSettingsController; use OC\Settings\Controller\SecuritySettingsController; use OC\Settings\Controller\UsersController; @@ -91,6 +92,15 @@ class Application extends App { $c->query('URLGenerator') ); }); + $container->registerService('LogSettingsController', function(IContainer $c) { + return new LogSettingsController( + $c->query('AppName'), + $c->query('Request'), + $c->query('Config'), + $c->query('L10N'), + $c->query('TimeFactory') + ); + }); /** * Middleware diff --git a/settings/controller/logsettingscontroller.php b/settings/controller/logsettingscontroller.php new file mode 100644 index 0000000000..759b466682 --- /dev/null +++ b/settings/controller/logsettingscontroller.php @@ -0,0 +1,126 @@ + + * + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Settings\Controller; + +use OCP\AppFramework\Controller; +use OCP\AppFramework\Http; +use OCP\AppFramework\Http\JSONResponse; +use OCP\AppFramework\Http\DataDownloadResponse; +use OCP\IL10N; +use OCP\AppFramework\Utility\ITimeFactory; +use OCP\IRequest; +use OCP\IConfig; + +/** + * Class LogSettingsController + * + * @package OC\Settings\Controller + */ +class LogSettingsController extends Controller { + /** + * @var \OCP\IConfig + */ + private $config; + + /** + * @var \OCP\IL10N + */ + private $l10n; + + /** + * @var \OCP\ITimeFactory + */ + private $timefactory; + + /** + * @param string $appName + * @param IRequest $request + * @param IConfig $config + */ + public function __construct($appName, + IRequest $request, + IConfig $config, + IL10N $l10n, + ITimeFactory $timeFactory) { + + parent::__construct($appName, $request); + $this->config = $config; + $this->l10n = $l10n; + $this->timefactory = $timeFactory; + } + + /** + * set log level for logger + * + * @param int $level + * @return JSONResponse + */ + public function setLogLevel($level) { + if ($level < 0 || $level > 4) { + return new JSONResponse([ + 'message' => (string) $this->l10n->t('log-level out of allowed range'), + ], Http::STATUS_BAD_REQUEST); + } + + $this->config->setSystemValue('loglevel', $level); + return new JSONResponse([ + 'level' => $level, + ]); + } + + /** + * get log entries from logfile + * + * @param int $count + * @param int $offset + * @return JSONResponse + */ + public function getEntries($count=50, $offset=0) { + return new JSONResponse([ + 'data' => \OC_Log_Owncloud::getEntries($count, $offset), + 'remain' => count(\OC_Log_Owncloud::getEntries(1, $offset + $count)) !== 0, + ]); + } + + /** + * download logfile + * + * @NoCSRFRequired + * + * @return DataDownloadResponse + */ + public function download() { + return new DataDownloadResponse( + json_encode(\OC_Log_Owncloud::getEntries(null, null)), + $this->getFilenameForDownload(), + 'application/json' + ); + } + + /** + * get filename for the logfile that's being downloaded + * + * @param int $timestamp (defaults to time()) + * @return string + */ + private function getFilenameForDownload($timestamp=null) { + $instanceId = $this->config->getSystemValue('instanceid'); + + $filename = implode([ + 'ownCloud', + $instanceId, + (!is_null($timestamp)) ? $timestamp : $this->timefactory->getTime() + ], '-'); + $filename .= '.log'; + + return $filename; + } +} diff --git a/settings/js/admin.js b/settings/js/admin.js index 059e48ebab..d00d083407 100644 --- a/settings/js/admin.js +++ b/settings/js/admin.js @@ -34,7 +34,7 @@ $(document).ready(function(){ $('#loglevel').change(function(){ - $.post(OC.filePath('settings','ajax','setloglevel.php'), { level: $(this).val() },function(){ + $.post(OC.generateUrl('/settings/admin/log/level'), {level: $(this).val()},function(){ OC.Log.reload(); } ); }); diff --git a/settings/js/log.js b/settings/js/log.js index 46d1bfefd5..c3a9a201e8 100644 --- a/settings/js/log.js +++ b/settings/js/log.js @@ -20,14 +20,12 @@ OC.Log = { loaded: 3,//are initially loaded getMore: function (count) { count = count || 10; - $.get(OC.filePath('settings', 'ajax', 'getlog.php'), {offset: OC.Log.loaded, count: count}, function (result) { - if (result.status === 'success') { - OC.Log.addEntries(result.data); - if (!result.remain) { - $('#moreLog').hide(); - } - $('#lessLog').show(); + $.get(OC.generateUrl('/settings/admin/log/entries'), {offset: OC.Log.loaded, count: count}, function (result) { + OC.Log.addEntries(result.data); + if (!result.remain) { + $('#moreLog').hide(); } + $('#lessLog').show(); }); }, showLess: function (count) { diff --git a/settings/routes.php b/settings/routes.php index 4be7785670..150746665d 100644 --- a/settings/routes.php +++ b/settings/routes.php @@ -14,7 +14,7 @@ $application->registerRoutes($this, array( 'groups' => array('url' => '/settings/users/groups'), 'users' => array('url' => '/settings/users/users') ), - 'routes' =>array( + 'routes' => array( array('name' => 'MailSettings#setMailSettings', 'url' => '/settings/admin/mailsettings', 'verb' => 'POST'), array('name' => 'MailSettings#storeCredentials', 'url' => '/settings/admin/mailsettings/credentials', 'verb' => 'POST'), array('name' => 'MailSettings#sendTestMail', 'url' => '/settings/admin/mailtest', 'verb' => 'POST'), @@ -24,6 +24,9 @@ $application->registerRoutes($this, array( array('name' => 'SecuritySettings#enforceSSLForSubdomains', 'url' => '/settings/admin/security/ssl/subdomains', 'verb' => 'POST'), array('name' => 'SecuritySettings#trustedDomains', 'url' => '/settings/admin/security/trustedDomains', 'verb' => 'POST'), array('name' => 'Users#setMailAddress', 'url' => '/settings/users/{id}/mailAddress', 'verb' => 'PUT'), + array('name' => 'LogSettings#setLogLevel', 'url' => '/settings/admin/log/level', 'verb' => 'POST'), + array('name' => 'LogSettings#getEntries', 'url' => '/settings/admin/log/entries', 'verb' => 'GET'), + array('name' => 'LogSettings#download', 'url' => '/settings/admin/log/download', 'verb' => 'GET'), ) )); @@ -87,10 +90,6 @@ $this->create('settings_ajax_uninstallapp', '/settings/ajax/uninstallapp.php') $this->create('settings_ajax_navigationdetect', '/settings/ajax/navigationdetect.php') ->actionInclude('settings/ajax/navigationdetect.php'); // admin -$this->create('settings_ajax_getlog', '/settings/ajax/getlog.php') - ->actionInclude('settings/ajax/getlog.php'); -$this->create('settings_ajax_setloglevel', '/settings/ajax/setloglevel.php') - ->actionInclude('settings/ajax/setloglevel.php'); $this->create('settings_ajax_excludegroups', '/settings/ajax/excludegroups.php') ->actionInclude('settings/ajax/excludegroups.php'); $this->create('settings_ajax_checksetup', '/settings/ajax/checksetup') diff --git a/settings/templates/admin.php b/settings/templates/admin.php index d04351c2d6..dc800271d5 100644 --- a/settings/templates/admin.php +++ b/settings/templates/admin.php @@ -462,6 +462,7 @@ if ($_['suggestedOverwriteWebroot']) { + @@ -484,11 +485,20 @@ if ($_['suggestedOverwriteWebroot']) {
+ 0): ?> + t('Download logfile'));?> + - + (100 * 1024 * 1024)): ?> +
+ + t('The logfile is bigger than 100MB. Downloading it may take some time!')); ?> + + +
diff --git a/tests/settings/controller/logsettingscontrollertest.php b/tests/settings/controller/logsettingscontrollertest.php new file mode 100644 index 0000000000..e80acfa75b --- /dev/null +++ b/tests/settings/controller/logsettingscontrollertest.php @@ -0,0 +1,79 @@ + + * + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ +namespace Test\Settings\Controller; + +use \OC\Settings\Application; + +/** + * @package OC\Settings\Controller + */ +class LogSettingsControllerTest extends \Test\TestCase { + + /** @var \OCP\AppFramework\IAppContainer */ + private $container; + + /** @var LogSettingsController */ + private $logSettingsController; + + protected function setUp() { + $app = new Application(); + $this->container = $app->getContainer(); + $this->container['Config'] = $this->getMockBuilder('\OCP\IConfig') + ->disableOriginalConstructor()->getMock(); + $this->container['AppName'] = 'settings'; + $this->logSettingsController = $this->container['LogSettingsController']; + } + + /** + * @dataProvider logLevelData + */ + public function testSetLogLevel($level, $inRange) { + if ($inRange) { + $this->container['Config'] + ->expects($this->once()) + ->method('setSystemValue') + ->with('loglevel', $level); + } + + $response = $this->logSettingsController->setLogLevel($level)->getData(); + + if ($inRange) { + $expectedResponse = ['level' => $level]; + } else { + $expectedResponse = ['message' => 'log-level out of allowed range']; + } + + $this->assertSame($expectedResponse, $response); + } + + public function logLevelData() { + return [ + [-1, false], + [0, true], + [1, true], + [2, true], + [3, true], + [4, true], + [5, false], + ]; + } + + public function testGetFilenameForDownload() { + $timestamp = 42; + $this->container['Config'] + ->expects($this->once()) + ->method('getSystemValue') + ->with('instanceid') + ->will($this->returnValue('0xF')); + $filename = \Test_Helper::invokePrivate($this->logSettingsController, 'getFilenameForDownload', [$timestamp]); + + $this->assertSame('ownCloud-0xF-42.log', $filename); + } +}