diff options
38 files changed, 713 insertions, 269 deletions
diff --git a/.gitignore b/.gitignore index 8c8b61d701b..25cb1b227f9 100644 --- a/.gitignore +++ b/.gitignore @@ -88,6 +88,7 @@ nbproject # Tests - auto-generated files /data-autotest /tests/coverage* +/tests/karma-coverage /tests/autoconfig* /tests/autotest* /tests/data/lorem-copy.txt diff --git a/.jshintrc b/.jshintrc new file mode 100644 index 00000000000..f40dd22b5fd --- /dev/null +++ b/.jshintrc @@ -0,0 +1,28 @@ +{ + "camelCase": true, + "eqeqeq": true, + "immed": true, + "latedef": false, + "noarg": true, + "nonbsp": true, + "undef": true, + "unused": true, + "trailing": true, + "maxparams": 5, + "curly": true, + "jquery": true, + "maxlen": 80, + "indent": 4, + "browser": true, + "globals": { + "console": true, + "it": true, + "itx": true, + "expect": true, + "describe": true, + "beforeEach": true, + "afterEach": true, + "sinon": true, + "fakeServer": true + } +} diff --git a/apps/files/index.php b/apps/files/index.php index 2ce8fdb065f..dd63f29bc28 100644 --- a/apps/files/index.php +++ b/apps/files/index.php @@ -101,6 +101,8 @@ if ($needUpgrade) { } else { // information about storage capacities $storageInfo=OC_Helper::getStorageInfo($dir); + $freeSpace=$storageInfo['free']; + $uploadLimit=OCP\Util::uploadLimit(); $maxUploadFilesize=OCP\Util::maxUploadFilesize($dir); $publicUploadEnabled = \OC_Appconfig::getValue('core', 'shareapi_allow_public_upload', 'yes'); // if the encryption app is disabled, than everything is fine (INIT_SUCCESSFUL status code) @@ -132,8 +134,10 @@ if ($needUpgrade) { $tmpl->assign('files', $files); $tmpl->assign('trash', $trashEnabled); $tmpl->assign('trashEmpty', $trashEmpty); - $tmpl->assign('uploadMaxFilesize', $maxUploadFilesize); + $tmpl->assign('uploadMaxFilesize', $maxUploadFilesize); // minimium of freeSpace and uploadLimit $tmpl->assign('uploadMaxHumanFilesize', OCP\Util::humanFileSize($maxUploadFilesize)); + $tmpl->assign('freeSpace', $freeSpace); + $tmpl->assign('uploadLimit', $uploadLimit); // PHP upload limit $tmpl->assign('allowZipDownload', intval(OCP\Config::getSystemValue('allowZipDownload', true))); $tmpl->assign('usedSpacePercent', (int)$storageInfo['relative']); $tmpl->assign('isPublic', false); diff --git a/apps/files/js/admin.js b/apps/files/js/admin.js index bfa96670635..f735079fcbe 100644 --- a/apps/files/js/admin.js +++ b/apps/files/js/admin.js @@ -1,3 +1,13 @@ +/* + * Copyright (c) 2014 + * + * This file is licensed under the Affero General Public License version 3 + * or later. + * + * See the COPYING-README file. + * + */ + function switchPublicFolder() { var publicEnable = $('#publicEnable').is(':checked'); @@ -10,7 +20,7 @@ function switchPublicFolder() $(document).ready(function(){ switchPublicFolder(); // Execute the function after loading DOM tree $('#publicEnable').click(function(){ - switchPublicFolder(); // To get rid of onClick() + switchPublicFolder(); // To get rid of onClick() }); $('#allowZipDownload').bind('change', function() { diff --git a/apps/files/js/file-upload.js b/apps/files/js/file-upload.js index 486273a910c..f962a7044a8 100644 --- a/apps/files/js/file-upload.js +++ b/apps/files/js/file-upload.js @@ -1,3 +1,13 @@ +/* + * Copyright (c) 2014 + * + * This file is licensed under the Affero General Public License version 3 + * or later. + * + * See the COPYING-README file. + * + */ + /** * The file upload code uses several hooks to interact with blueimps jQuery file upload library: * 1. the core upload handling hooks are added when initializing the plugin, @@ -8,6 +18,8 @@ * - TODO music upload button */ +/* global OC, t, n */ + /** * Function that will allow us to know if Ajax uploads are supported * @link https://github.com/New-Bamboo/example-ajax-upload/blob/master/public/index.html @@ -241,10 +253,22 @@ $(document).ready(function() { // add size selection.totalBytes += file.size; - //check max upload size - if (selection.totalBytes > $('#max_upload').val()) { + // check PHP upload limit + if (selection.totalBytes > $('#upload_limit').val()) { + data.textStatus = 'sizeexceedlimit'; + data.errorThrown = t('files', 'Total file size {size1} exceeds upload limit {size2}', { + 'size1': humanFileSize(selection.totalBytes), + 'size2': humanFileSize($('#upload_limit').val()) + }); + } + + // check free space + if (selection.totalBytes > $('#free_space').val()) { data.textStatus = 'notenoughspace'; - data.errorThrown = t('files', 'Not enough space available'); + data.errorThrown = t('files', 'Not enough free space, you are uploading {size1} but only {size2} is left', { + 'size1': humanFileSize(selection.totalBytes), + 'size2': humanFileSize($('#free_space').val()) + }); } // end upload for whole selection on error diff --git a/apps/files/js/fileactions.js b/apps/files/js/fileactions.js index f36457f01a8..9a69d7b3688 100644 --- a/apps/files/js/fileactions.js +++ b/apps/files/js/fileactions.js @@ -1,3 +1,15 @@ +/* + * Copyright (c) 2014 + * + * This file is licensed under the Affero General Public License version 3 + * or later. + * + * See the COPYING-README file. + * + */ + +/* global OC, FileList */ +/* global trashBinApp */ var FileActions = { actions: {}, defaults: {}, @@ -45,8 +57,9 @@ var FileActions = { return filteredActions; }, getDefault: function (mime, type, permissions) { + var mimePart; if (mime) { - var mimePart = mime.substr(0, mime.indexOf('/')); + mimePart = mime.substr(0, mime.indexOf('/')); } var name = false; if (mime && FileActions.defaults[mime]) { @@ -141,13 +154,14 @@ var FileActions = { parent.parent().children().last().find('.action.delete').remove(); if (actions['Delete']) { var img = FileActions.icons['Delete']; + var html; if (img.call) { img = img(file); } if (typeof trashBinApp !== 'undefined' && trashBinApp) { - var html = '<a href="#" original-title="' + t('files', 'Delete permanently') + '" class="action delete delete-icon" />'; + html = '<a href="#" original-title="' + t('files', 'Delete permanently') + '" class="action delete delete-icon" />'; } else { - var html = '<a href="#" class="action delete delete-icon" />'; + html = '<a href="#" class="action delete delete-icon" />'; } var element = $(html); element.data('action', actions['Delete']); @@ -174,10 +188,11 @@ var FileActions = { }; $(document).ready(function () { + var downloadScope; if ($('#allowZipDownload').val() == 1) { - var downloadScope = 'all'; + downloadScope = 'all'; } else { - var downloadScope = 'file'; + downloadScope = 'file'; } if (typeof disableDownloadActions == 'undefined' || !disableDownloadActions) { diff --git a/apps/files/js/filelist.js b/apps/files/js/filelist.js index 23b31e72467..81c52e2a863 100644 --- a/apps/files/js/filelist.js +++ b/apps/files/js/filelist.js @@ -1,4 +1,16 @@ -var FileList={ +/* + * Copyright (c) 2014 + * + * This file is licensed under the Affero General Public License version 3 + * or later. + * + * See the COPYING-README file. + * + */ + +/* global OC, t, n, FileList, FileActions, Files */ +/* global procesSelection, dragOptions, SVGSupport, replaceSVG */ +window.FileList={ useUndo:true, postProcessList: function() { $('#fileList tr').each(function() { @@ -191,6 +203,7 @@ var FileList={ return OC.linkTo('files', 'index.php')+"?dir="+ encodeURIComponent(dir).replace(/%2F/g, '/'); }, setCurrentDir: function(targetDir, changeUrl) { + var url; $('#dir').val(targetDir); if (changeUrl !== false) { if (window.history.pushState && changeUrl !== false) { @@ -834,7 +847,7 @@ $(document).ready(function() { {name: 'requesttoken', value: oc_requesttoken} ]; }; - } + } }); file_upload_start.on('fileuploadadd', function(e, data) { diff --git a/apps/files/js/files.js b/apps/files/js/files.js index d794a1584de..a535700c1b3 100644 --- a/apps/files/js/files.js +++ b/apps/files/js/files.js @@ -1,4 +1,16 @@ -Files={ +/* + * Copyright (c) 2014 + * + * This file is licensed under the Affero General Public License version 3 + * or later. + * + * See the COPYING-README file. + * + */ + +/* global OC, t, n, FileList, FileActions */ +/* global getURLParameter, isPublic */ +var Files = { // file space size sync _updateStorageStatistics: function() { Files._updateStorageStatisticsTimeout = null; @@ -41,6 +53,7 @@ Files={ } if (response.data !== undefined && response.data.uploadMaxFilesize !== undefined) { $('#max_upload').val(response.data.uploadMaxFilesize); + $('#free_space').val(response.data.freeSpace); $('#upload.button').attr('original-title', response.data.maxHumanFilesize); $('#usedSpacePercent').val(response.data.usedSpacePercent); Files.displayStorageWarnings(); @@ -67,17 +80,25 @@ Files={ return fileName; }, - isFileNameValid:function (name) { - if (name === '.') { - throw t('files', '\'.\' is an invalid file name.'); - } else if (name.length === 0) { + /** + * Checks whether the given file name is valid. + * @param name file name to check + * @return true if the file name is valid. + * Throws a string exception with an error message if + * the file name is not valid + */ + isFileNameValid: function (name) { + var trimmedName = name.trim(); + if (trimmedName === '.' || trimmedName === '..') { + throw t('files', '"{name}" is an invalid file name.', {name: name}); + } else if (trimmedName.length === 0) { throw t('files', 'File name cannot be empty.'); } - // check for invalid characters - var invalid_characters = ['\\', '/', '<', '>', ':', '"', '|', '?', '*']; + var invalid_characters = + ['\\', '/', '<', '>', ':', '"', '|', '?', '*', '\n']; for (var i = 0; i < invalid_characters.length; i++) { - if (name.indexOf(invalid_characters[i]) !== -1) { + if (trimmedName.indexOf(invalid_characters[i]) !== -1) { throw t('files', "Invalid name, '\\', '/', '<', '>', ':', '\"', '|', '?' and '*' are not allowed."); } } @@ -654,10 +675,10 @@ function procesSelection() { var totalSize = 0; for(var i=0; i<selectedFiles.length; i++) { totalSize+=selectedFiles[i].size; - }; + } for(var i=0; i<selectedFolders.length; i++) { totalSize+=selectedFolders[i].size; - }; + } $('#headerSize').text(humanFileSize(totalSize)); var selection = ''; if (selectedFolders.length > 0) { @@ -769,10 +790,11 @@ Files.lazyLoadPreview = function(path, mime, ready, width, height, etag) { } img.src = previewURL; }); -} +}; function getUniqueName(name) { if (FileList.findFileEl(name).exists()) { + var numMatch; var parts=name.split('.'); var extension = ""; if (parts.length > 1) { @@ -806,7 +828,7 @@ function checkTrashStatus() { function onClickBreadcrumb(e) { var $el = $(e.target).closest('.crumb'), - $targetDir = $el.data('dir'); + $targetDir = $el.data('dir'), isPublic = !!$('#isPublic').val(); if ($targetDir !== undefined && !isPublic) { diff --git a/apps/files/js/upgrade.js b/apps/files/js/upgrade.js index 02d57fc9e6c..714adf824a1 100644 --- a/apps/files/js/upgrade.js +++ b/apps/files/js/upgrade.js @@ -1,3 +1,14 @@ +/* + * Copyright (c) 2014 + * + * This file is licensed under the Affero General Public License version 3 + * or later. + * + * See the COPYING-README file. + * + */ + +/* global OC */ $(document).ready(function () { var eventSource, total, bar = $('#progressbar'); console.log('start'); diff --git a/apps/files/js/upload.js b/apps/files/js/upload.js index 9d9f61f600e..617cf4b1c1d 100644 --- a/apps/files/js/upload.js +++ b/apps/files/js/upload.js @@ -1,3 +1,14 @@ +/* + * Copyright (c) 2014 + * + * This file is licensed under the Affero General Public License version 3 + * or later. + * + * See the COPYING-README file. + * + */ + +/* global OC */ function Upload(fileSelector) { if ($.support.xhrFileUpload) { return new XHRUpload(fileSelector.target.files); diff --git a/apps/files/lib/helper.php b/apps/files/lib/helper.php index eaff28178ea..21d1f50e587 100644 --- a/apps/files/lib/helper.php +++ b/apps/files/lib/helper.php @@ -15,6 +15,7 @@ class Helper return array('uploadMaxFilesize' => $maxUploadFilesize, 'maxHumanFilesize' => $maxHumanFilesize, + 'freeSpace' => $storageInfo['free'], 'usedSpacePercent' => (int)$storageInfo['relative']); } diff --git a/apps/files/templates/index.php b/apps/files/templates/index.php index ff78f0ca551..939043b2c9f 100644 --- a/apps/files/templates/index.php +++ b/apps/files/templates/index.php @@ -17,9 +17,10 @@ <div id="upload" class="button" title="<?php p($l->t('Upload') . ' max. '.$_['uploadMaxHumanFilesize']) ?>"> <?php if($_['uploadMaxFilesize'] >= 0):?> - <input type="hidden" name="MAX_FILE_SIZE" id="max_upload" - value="<?php p($_['uploadMaxFilesize']) ?>"> + <input type="hidden" id="max_upload" name="MAX_FILE_SIZE" value="<?php p($_['uploadMaxFilesize']) ?>"> <?php endif;?> + <input type="hidden" id="upload_limit" value="<?php p($_['uploadLimit']) ?>"> + <input type="hidden" id="free_space" value="<?php p($_['freeSpace']) ?>"> <?php if(isset($_['dirToken'])):?> <input type="hidden" id="publicUploadRequestToken" name="requesttoken" value="<?php p($_['requesttoken']) ?>" /> <input type="hidden" id="dirToken" name="dirToken" value="<?php p($_['dirToken']) ?>" /> diff --git a/apps/files/tests/js/fileactionsSpec.js b/apps/files/tests/js/fileactionsSpec.js index e185cf2f654..8bbc1d3d141 100644 --- a/apps/files/tests/js/fileactionsSpec.js +++ b/apps/files/tests/js/fileactionsSpec.js @@ -18,7 +18,10 @@ * License along with this library. If not, see <http://www.gnu.org/licenses/>. * */ + +/* global OC, FileActions, FileList */ describe('FileActions tests', function() { + var $filesTable; beforeEach(function() { // init horrible parameters var $body = $('body'); diff --git a/apps/files/tests/js/filelistSpec.js b/apps/files/tests/js/filelistSpec.js index 61e026c0725..c26e65fc4de 100644 --- a/apps/files/tests/js/filelistSpec.js +++ b/apps/files/tests/js/filelistSpec.js @@ -18,6 +18,8 @@ * License along with this library. If not, see <http://www.gnu.org/licenses/>. * */ + +/* global OC, FileList */ describe('FileList tests', function() { beforeEach(function() { // init horrible parameters diff --git a/apps/files/tests/js/filesSpec.js b/apps/files/tests/js/filesSpec.js index 9d0a2e4f9d7..018c8ef0f3c 100644 --- a/apps/files/tests/js/filesSpec.js +++ b/apps/files/tests/js/filesSpec.js @@ -18,6 +18,8 @@ * License along with this library. If not, see <http://www.gnu.org/licenses/>. * */ + +/* global Files */ describe('Files tests', function() { describe('File name validation', function() { it('Validates correct file names', function() { @@ -36,12 +38,14 @@ describe('Files tests', function() { 'und Ümläüte sind auch willkommen' ]; for ( var i = 0; i < fileNames.length; i++ ) { + var error = false; try { expect(Files.isFileNameValid(fileNames[i])).toEqual(true); } catch (e) { - fail(); + error = e; } + expect(error).toEqual(false); } }); it('Detects invalid file names', function() { @@ -69,7 +73,7 @@ describe('Files tests', function() { var threwException = false; try { Files.isFileNameValid(fileNames[i]); - fail(); + console.error('Invalid file name not detected:', fileNames[i]); } catch (e) { threwException = true; diff --git a/apps/files_sharing/public.php b/apps/files_sharing/public.php index 0ca923fff08..b187da41324 100644 --- a/apps/files_sharing/public.php +++ b/apps/files_sharing/public.php @@ -143,6 +143,8 @@ if (isset($path)) { OCP\Util::addScript('files', 'jquery.iframe-transport'); OCP\Util::addScript('files', 'jquery.fileupload'); $maxUploadFilesize=OCP\Util::maxUploadFilesize($path); + $freeSpace=OCP\Util::freeSpace($dir); + $uploadLimit=OCP\Util::uploadLimit(); $tmpl = new OCP\Template('files_sharing', 'public', 'base'); $tmpl->assign('uidOwner', $shareOwner); $tmpl->assign('displayName', \OCP\User::getDisplayName($shareOwner)); @@ -162,6 +164,8 @@ if (isset($path)) { } $tmpl->assign('uploadMaxFilesize', $maxUploadFilesize); $tmpl->assign('uploadMaxHumanFilesize', OCP\Util::humanFileSize($maxUploadFilesize)); + $tmpl->assign('freeSpace', $freeSpace); + $tmpl->assign('uploadLimit', $uploadLimit); // PHP upload limit $urlLinkIdentifiers= (isset($token)?'&t='.$token:'') .(isset($_GET['dir'])?'&dir='.$_GET['dir']:'') diff --git a/apps/user_ldap/lib/connection.php b/apps/user_ldap/lib/connection.php index c4e4efd0483..7fbabda7106 100644 --- a/apps/user_ldap/lib/connection.php +++ b/apps/user_ldap/lib/connection.php @@ -52,7 +52,7 @@ class Connection extends LDAPUtility { $this->configID = $configID; $this->configuration = new Configuration($configPrefix, !is_null($configID)); - $memcache = new \OC\Memcache\Factory(); + $memcache = \OC::$server->getMemCacheFactory(); if($memcache->isAvailable()) { $this->cache = $memcache->create(); } else { diff --git a/autotest-js.sh b/autotest-js.sh index 78f4948e7ad..8b9a106b021 100755 --- a/autotest-js.sh +++ b/autotest-js.sh @@ -33,5 +33,5 @@ then exit 2 fi -KARMA_TESTSUITE="$1" $KARMA start tests/karma.config.js --single-run +NODE_PATH='build/node_modules' KARMA_TESTSUITE="$1" $KARMA start tests/karma.config.js --single-run diff --git a/core/js/core.json b/core/js/core.json index 79cfc42f587..4beab7cf796 100644 --- a/core/js/core.json +++ b/core/js/core.json @@ -1,28 +1,23 @@ { + "libraries": [ + "jquery-1.10.0.min.js", + "jquery-migrate-1.2.1.min.js", + "jquery-ui-1.10.0.custom.js", + "jquery-showpassword.js", + "jquery.infieldlabel.js", + "jquery.placeholder.js", + "jquery-tipsy.js" + ], "modules": [ - "jquery-1.10.0.min.js", - "jquery-migrate-1.2.1.min.js", - "jquery-ui-1.10.0.custom.js", - "jquery-showpassword.js", - "jquery.infieldlabel.js", - "jquery.placeholder.js", - "jquery-tipsy.js", - "compatibility.js", - "jquery.ocdialog.js", - "oc-dialogs.js", - "js.js", - "octemplate.js", - "eventsource.js", - "config.js", - "multiselect.js", - "search.js", - "router.js", - "oc-requesttoken.js", - "styles.js", - "apps.js", - "fixes.js", - "jquery-ui-2.10.0.custom.js", - "jquery-tipsy.js", - "jquery.ocdialog.js" + "compatibility.js", + "jquery.ocdialog.js", + "oc-dialogs.js", + "js.js", + "octemplate.js", + "eventsource.js", + "config.js", + "multiselect.js", + "router.js", + "oc-requesttoken.js" ] } diff --git a/core/js/tests/specs/coreSpec.js b/core/js/tests/specs/coreSpec.js index 18652d4177f..478505e9287 100644 --- a/core/js/tests/specs/coreSpec.js +++ b/core/js/tests/specs/coreSpec.js @@ -18,6 +18,8 @@ * License along with this library. If not, see <http://www.gnu.org/licenses/>. * */ + +/* global OC */ describe('Core base tests', function() { describe('Base values', function() { it('Sets webroots', function() { @@ -25,6 +27,103 @@ describe('Core base tests', function() { expect(OC.appswebroots).toBeDefined(); }); }); + describe('basename', function() { + it('Returns the nothing if no file name given', function() { + expect(OC.basename('')).toEqual(''); + }); + it('Returns the nothing if dir is root', function() { + expect(OC.basename('/')).toEqual(''); + }); + it('Returns the same name if no path given', function() { + expect(OC.basename('some name.txt')).toEqual('some name.txt'); + }); + it('Returns the base name if root path given', function() { + expect(OC.basename('/some name.txt')).toEqual('some name.txt'); + }); + it('Returns the base name if double root path given', function() { + expect(OC.basename('//some name.txt')).toEqual('some name.txt'); + }); + it('Returns the base name if subdir given without root', function() { + expect(OC.basename('subdir/some name.txt')).toEqual('some name.txt'); + }); + it('Returns the base name if subdir given with root', function() { + expect(OC.basename('/subdir/some name.txt')).toEqual('some name.txt'); + }); + it('Returns the base name if subdir given with double root', function() { + expect(OC.basename('//subdir/some name.txt')).toEqual('some name.txt'); + }); + it('Returns the base name if subdir has dot', function() { + expect(OC.basename('/subdir.dat/some name.txt')).toEqual('some name.txt'); + }); + it('Returns dot if file name is dot', function() { + expect(OC.basename('/subdir/.')).toEqual('.'); + }); + // TODO: fix the source to make it work like PHP's basename + it('Returns the dir itself if no file name given', function() { + // TODO: fix the source to make it work like PHP's dirname + // expect(OC.basename('subdir/')).toEqual('subdir'); + expect(OC.basename('subdir/')).toEqual(''); + }); + it('Returns the dir itself if no file name given with root', function() { + // TODO: fix the source to make it work like PHP's dirname + // expect(OC.basename('/subdir/')).toEqual('subdir'); + expect(OC.basename('/subdir/')).toEqual(''); + }); + }); + describe('dirname', function() { + it('Returns the nothing if no file name given', function() { + expect(OC.dirname('')).toEqual(''); + }); + it('Returns the root if dir is root', function() { + // TODO: fix the source to make it work like PHP's dirname + // expect(OC.dirname('/')).toEqual('/'); + expect(OC.dirname('/')).toEqual(''); + }); + it('Returns the root if dir is double root', function() { + // TODO: fix the source to make it work like PHP's dirname + // expect(OC.dirname('//')).toEqual('/'); + expect(OC.dirname('//')).toEqual('/'); // oh no... + }); + it('Returns dot if dir is dot', function() { + expect(OC.dirname('.')).toEqual('.'); + }); + it('Returns dot if no root given', function() { + // TODO: fix the source to make it work like PHP's dirname + // expect(OC.dirname('some dir')).toEqual('.'); + expect(OC.dirname('some dir')).toEqual('some dir'); // oh no... + }); + it('Returns the dir name if file name and root path given', function() { + // TODO: fix the source to make it work like PHP's dirname + // expect(OC.dirname('/some name.txt')).toEqual('/'); + expect(OC.dirname('/some name.txt')).toEqual(''); + }); + it('Returns the dir name if double root path given', function() { + expect(OC.dirname('//some name.txt')).toEqual('/'); // how lucky... + }); + it('Returns the dir name if subdir given without root', function() { + expect(OC.dirname('subdir/some name.txt')).toEqual('subdir'); + }); + it('Returns the dir name if subdir given with root', function() { + expect(OC.dirname('/subdir/some name.txt')).toEqual('/subdir'); + }); + it('Returns the dir name if subdir given with double root', function() { + // TODO: fix the source to make it work like PHP's dirname + // expect(OC.dirname('//subdir/some name.txt')).toEqual('/subdir'); + expect(OC.dirname('//subdir/some name.txt')).toEqual('//subdir'); // oh... + }); + it('Returns the dir name if subdir has dot', function() { + expect(OC.dirname('/subdir.dat/some name.txt')).toEqual('/subdir.dat'); + }); + it('Returns the dir name if file name is dot', function() { + expect(OC.dirname('/subdir/.')).toEqual('/subdir'); + }); + it('Returns the dir name if no file name given', function() { + expect(OC.dirname('subdir/')).toEqual('subdir'); + }); + it('Returns the dir name if no file name given with root', function() { + expect(OC.dirname('/subdir/')).toEqual('/subdir'); + }); + }); describe('Link functions', function() { var TESTAPP = 'testapp'; var TESTAPP_ROOT = OC.webroot + '/appsx/testapp'; diff --git a/core/setup.php b/core/setup.php deleted file mode 100644 index 958376b2cce..00000000000 --- a/core/setup.php +++ /dev/null @@ -1,73 +0,0 @@ -<?php - -// Check for autosetup: -$autosetup_file = OC::$SERVERROOT."/config/autoconfig.php"; -if( file_exists( $autosetup_file )) { - OC_Log::write('core', 'Autoconfig file found, setting up owncloud...', OC_Log::INFO); - include $autosetup_file; - $_POST = array_merge ($_POST, $AUTOCONFIG); - $_REQUEST = array_merge ($_REQUEST, $AUTOCONFIG); -} - -$dbIsSet = isset($_POST['dbtype']); -$directoryIsSet = isset($_POST['directory']); -$adminAccountIsSet = isset($_POST['adminlogin']); - -if ($dbIsSet AND $directoryIsSet AND $adminAccountIsSet) { - $_POST['install'] = 'true'; - if( file_exists( $autosetup_file )) { - unlink($autosetup_file); - } -} - -OC_Util::addScript( '3rdparty', 'strengthify/jquery.strengthify' ); -OC_Util::addStyle( '3rdparty', 'strengthify/strengthify' ); -OC_Util::addScript('setup'); - -$hasSQLite = class_exists('SQLite3'); -$hasMySQL = is_callable('mysql_connect'); -$hasPostgreSQL = is_callable('pg_connect'); -$hasOracle = is_callable('oci_connect'); -$hasMSSQL = is_callable('sqlsrv_connect'); -$datadir = OC_Config::getValue('datadirectory', OC::$SERVERROOT.'/data'); -$vulnerableToNullByte = false; -if(@file_exists(__FILE__."\0Nullbyte")) { // Check if the used PHP version is vulnerable to the NULL Byte attack (CVE-2006-7243) - $vulnerableToNullByte = true; -} - -// Protect data directory here, so we can test if the protection is working -OC_Setup::protectDataDirectory(); - -$opts = array( - 'hasSQLite' => $hasSQLite, - 'hasMySQL' => $hasMySQL, - 'hasPostgreSQL' => $hasPostgreSQL, - 'hasOracle' => $hasOracle, - 'hasMSSQL' => $hasMSSQL, - 'directory' => $datadir, - 'secureRNG' => OC_Util::secureRNGAvailable(), - 'htaccessWorking' => OC_Util::isHtAccessWorking(), - 'vulnerableToNullByte' => $vulnerableToNullByte, - 'errors' => array(), - 'dbIsSet' => $dbIsSet, - 'directoryIsSet' => $directoryIsSet, -); - -if(isset($_POST['install']) AND $_POST['install']=='true') { - // We have to launch the installation process : - $e = OC_Setup::install($_POST); - $errors = array('errors' => $e); - - if(count($e) > 0) { - //OC_Template::printGuestPage("", "error", array("errors" => $errors)); - $options = array_merge($_POST, $opts, $errors); - OC_Template::printGuestPage("", "installation", $options); - } - else { - header( 'Location: '.OC_Helper::linkToRoute( 'post_setup_check' )); - exit(); - } -} -else { - OC_Template::printGuestPage("", "installation", $opts); -} diff --git a/core/setup/controller.php b/core/setup/controller.php new file mode 100644 index 00000000000..c628bda609b --- /dev/null +++ b/core/setup/controller.php @@ -0,0 +1,138 @@ +<?php +/** + * Copyright (c) 2013 Bart Visscher <bartv@thisnet.nl> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Core\Setup; + +class Controller { + public function run($post) { + // Check for autosetup: + $post = $this->loadAutoConfig($post); + $opts = $this->getSystemInfo(); + + if(isset($post['install']) AND $post['install']=='true') { + // We have to launch the installation process : + $e = \OC_Setup::install($post); + $errors = array('errors' => $e); + + if(count($e) > 0) { + $options = array_merge($post, $opts, $errors); + $this->display($options); + } + else { + $this->finishSetup(); + } + } + else { + $this->display($opts); + } + } + + public function display($post) { + $defaults = array( + 'adminlogin' => '', + 'adminpass' => '', + 'dbuser' => '', + 'dbpass' => '', + 'dbname' => '', + 'dbtablespace' => '', + 'dbhost' => '', + ); + $parameters = array_merge($defaults, $post); + + \OC_Util::addScript( '3rdparty', 'strengthify/jquery.strengthify' ); + \OC_Util::addStyle( '3rdparty', 'strengthify/strengthify' ); + \OC_Util::addScript('setup'); + \OC_Template::printGuestPage('', 'installation', $parameters); + } + + public function finishSetup() { + header( 'Location: '.\OC_Helper::linkToRoute( 'post_setup_check' )); + exit(); + } + + public function loadAutoConfig($post) { + $dbIsSet = isset($post['dbtype']); + $directoryIsSet = isset($post['directory']); + $adminAccountIsSet = isset($post['adminlogin']); + + $autosetup_file = \OC::$SERVERROOT.'/config/autoconfig.php'; + if( file_exists( $autosetup_file )) { + \OC_Log::write('core', 'Autoconfig file found, setting up owncloud...', \OC_Log::INFO); + include $autosetup_file; + $post = array_merge ($post, $AUTOCONFIG); + } + + if ($dbIsSet AND $directoryIsSet AND $adminAccountIsSet) { + $post['install'] = 'true'; + if( file_exists( $autosetup_file )) { + unlink($autosetup_file); + } + } + $post['dbIsSet'] = $dbIsSet; + $post['directoryIsSet'] = $directoryIsSet; + + return $post; + } + + public function getSystemInfo() { + $hasSQLite = class_exists('SQLite3'); + $hasMySQL = is_callable('mysql_connect'); + $hasPostgreSQL = is_callable('pg_connect'); + $hasOracle = is_callable('oci_connect'); + $hasMSSQL = is_callable('sqlsrv_connect'); + $databases = array(); + if ($hasSQLite) { + $databases['sqlite'] = 'SQLite'; + } + if ($hasMySQL) { + $databases['mysql'] = 'MySQL'; + } + if ($hasPostgreSQL) { + $databases['pgsql'] = 'PostgreSQL'; + } + if ($hasOracle) { + $databases['oci'] = 'Oracle'; + } + if ($hasMSSQL) { + $databases['mssql'] = 'MS SQL'; + } + $datadir = \OC_Config::getValue('datadirectory', \OC::$SERVERROOT.'/data'); + $vulnerableToNullByte = false; + if(@file_exists(__FILE__."\0Nullbyte")) { // Check if the used PHP version is vulnerable to the NULL Byte attack (CVE-2006-7243) + $vulnerableToNullByte = true; + } + + $errors = array(); + + // Protect data directory here, so we can test if the protection is working + \OC_Setup::protectDataDirectory(); + try { + $htaccessWorking = \OC_Util::isHtAccessWorking(); + } catch (\OC\HintException $e) { + $errors[] = array( + 'error' => $e->getMessage(), + 'hint' => $e->getHint() + ); + $htaccessWorking = false; + } + + return array( + 'hasSQLite' => $hasSQLite, + 'hasMySQL' => $hasMySQL, + 'hasPostgreSQL' => $hasPostgreSQL, + 'hasOracle' => $hasOracle, + 'hasMSSQL' => $hasMSSQL, + 'databases' => $databases, + 'directory' => $datadir, + 'secureRNG' => \OC_Util::secureRNGAvailable(), + 'htaccessWorking' => $htaccessWorking, + 'vulnerableToNullByte' => $vulnerableToNullByte, + 'errors' => $errors, + ); + } +} diff --git a/core/templates/installation.php b/core/templates/installation.php index 182fc83a4d4..9670a5e9ee5 100644 --- a/core/templates/installation.php +++ b/core/templates/installation.php @@ -48,13 +48,13 @@ <legend><?php print_unescaped($l->t( 'Create an <strong>admin account</strong>' )); ?></legend> <p class="infield grouptop"> <input type="text" name="adminlogin" id="adminlogin" placeholder="" - value="<?php p(OC_Helper::init_var('adminlogin')); ?>" autocomplete="off" autofocus required /> + value="<?php p($_['adminlogin']); ?>" autocomplete="off" autofocus required /> <label for="adminlogin" class="infield"><?php p($l->t( 'Username' )); ?></label> <img class="svg" src="<?php p(image_path('', 'actions/user.svg')); ?>" alt="" /> </p> <p class="infield groupbottom"> <input type="password" name="adminpass" data-typetoggle="#show" id="adminpass" placeholder="" - value="<?php p(OC_Helper::init_var('adminpass')); ?>" required /> + value="<?php p($_['adminpass']); ?>" required /> <label for="adminpass" class="infield"><?php p($l->t( 'Password' )); ?></label> <img class="svg" id="adminpass-icon" src="<?php print_unescaped(image_path('', 'actions/password.svg')); ?>" alt="" /> <input type="checkbox" id="show" name="show" /> @@ -75,7 +75,7 @@ <label for="directory"><?php p($l->t( 'Data folder' )); ?></label> <input type="text" name="directory" id="directory" placeholder="<?php p(OC::$SERVERROOT."/data"); ?>" - value="<?php p(OC_Helper::init_var('directory', $_['directory'])); ?>" /> + value="<?php p($_['directory']); ?>" /> </div> </fieldset> <?php endif; ?> @@ -86,62 +86,16 @@ $hasOtherDB = true; else $hasOtherDB =false; //other than SQLite ?> <legend><?php p($l->t( 'Configure the database' )); ?></legend> <div id="selectDbType"> - <?php if($_['hasSQLite']): ?> - <input type='hidden' id='hasSQLite' value="true" /> - <?php if(!$hasOtherDB): ?> - <p>SQLite <?php p($l->t( 'will be used' )); ?>.</p> - <input type="hidden" id="dbtype" name="dbtype" value="sqlite" /> + <?php foreach($_['databases'] as $type => $label): ?> + <?php if(count($_['databases']) === 1): ?> + <p class="info"><?php p($label . ' ' . $l->t( 'will be used' )); ?>.</p> + <input type="hidden" id="dbtype" name="dbtype" value="<?php p($type) ?>" /> <?php else: ?> - <input type="radio" name="dbtype" value="sqlite" id="sqlite" - <?php OC_Helper::init_radio('dbtype', 'sqlite', 'sqlite'); ?>/> - <label class="sqlite" for="sqlite">SQLite</label> - <?php endif; ?> - <?php endif; ?> - - <?php if($_['hasMySQL']): ?> - <input type='hidden' id='hasMySQL' value='true'/> - <?php if(!$_['hasSQLite'] and !$_['hasPostgreSQL'] and !$_['hasOracle'] and !$_['hasMSSQL']): ?> - <p>MySQL <?php p($l->t( 'will be used' )); ?>.</p> - <input type="hidden" id="dbtype" name="dbtype" value="mysql" /> - <?php else: ?> - <input type="radio" name="dbtype" value="mysql" id="mysql" - <?php OC_Helper::init_radio('dbtype', 'mysql', 'sqlite'); ?>/> - <label class="mysql" for="mysql">MySQL</label> - <?php endif; ?> - <?php endif; ?> - - <?php if($_['hasPostgreSQL']): ?> - <?php if(!$_['hasSQLite'] and !$_['hasMySQL'] and !$_['hasOracle'] and !$_['hasMSSQL']): ?> - <p>PostgreSQL <?php p($l->t( 'will be used' )); ?>.</p> - <input type="hidden" id="dbtype" name="dbtype" value="pgsql" /> - <?php else: ?> - <label class="pgsql" for="pgsql">PostgreSQL</label> - <input type="radio" name="dbtype" value='pgsql' id="pgsql" - <?php OC_Helper::init_radio('dbtype', 'pgsql', 'sqlite'); ?>/> - <?php endif; ?> - <?php endif; ?> - - <?php if($_['hasOracle']): ?> - <?php if(!$_['hasSQLite'] and !$_['hasMySQL'] and !$_['hasPostgreSQL'] and !$_['hasMSSQL']): ?> - <p>Oracle <?php p($l->t( 'will be used' )); ?>.</p> - <input type="hidden" id="dbtype" name="dbtype" value="oci" /> - <?php else: ?> - <label class="oci" for="oci">Oracle</label> - <input type="radio" name="dbtype" value='oci' id="oci" - <?php OC_Helper::init_radio('dbtype', 'oci', 'sqlite'); ?>/> - <?php endif; ?> - <?php endif; ?> - - <?php if($_['hasMSSQL']): ?> - <input type='hidden' id='hasMSSQL' value='true'/> - <?php if(!$_['hasSQLite'] and !$_['hasMySQL'] and !$_['hasPostgreSQL'] and !$_['hasOracle']): ?> - <p>MS SQL <?php p($l->t( 'will be used' )); ?>.</p> - <input type="hidden" id="dbtype" name="dbtype" value="mssql" /> - <?php else: ?> - <label class="mssql" for="mssql">MS SQL</label> - <input type="radio" name="dbtype" value='mssql' id="mssql" <?php OC_Helper::init_radio('dbtype', 'mssql', 'sqlite'); ?>/> - <?php endif; ?> + <input type="radio" name="dbtype" value="<?php p($type) ?>" id="<?php p($type) ?>" + <?php p($_['dbtype'] === $type ? 'checked="checked" ' : '') ?>/> + <label class="<?php p($type) ?>" for="<?php p($type) ?>"><?php p($label) ?></label> <?php endif; ?> + <?php endforeach; ?> </div> <?php if($hasOtherDB): ?> @@ -149,11 +103,11 @@ <p class="infield grouptop"> <label for="dbuser" class="infield"><?php p($l->t( 'Database user' )); ?></label> <input type="text" name="dbuser" id="dbuser" placeholder="" - value="<?php p(OC_Helper::init_var('dbuser')); ?>" autocomplete="off" /> + value="<?php p($_['dbuser']); ?>" autocomplete="off" /> </p> <p class="infield groupmiddle"> <input type="password" name="dbpass" id="dbpass" placeholder="" data-typetoggle="#dbpassword" - value="<?php p(OC_Helper::init_var('dbpass')); ?>" /> + value="<?php p($_['dbpass']); ?>" /> <label for="dbpass" class="infield"><?php p($l->t( 'Database password' )); ?></label> <input type="checkbox" id="dbpassword" name="dbpassword" /> <label for="dbpassword"></label> @@ -161,7 +115,7 @@ <p class="infield groupmiddle"> <label for="dbname" class="infield"><?php p($l->t( 'Database name' )); ?></label> <input type="text" name="dbname" id="dbname" placeholder="" - value="<?php p(OC_Helper::init_var('dbname')); ?>" + value="<?php p($_['dbname']); ?>" autocomplete="off" pattern="[0-9a-zA-Z$_-]+" /> </p> <?php if($_['hasOracle']): ?> @@ -169,14 +123,14 @@ <p class="infield groupmiddle"> <label for="dbtablespace" class="infield"><?php p($l->t( 'Database tablespace' )); ?></label> <input type="text" name="dbtablespace" id="dbtablespace" placeholder="" - value="<?php p(OC_Helper::init_var('dbtablespace')); ?>" autocomplete="off" /> + value="<?php p($_['dbtablespace']); ?>" autocomplete="off" /> </p> </div> <?php endif; ?> <p class="infield groupbottom"> <label for="dbhost" class="infield"><?php p($l->t( 'Database host' )); ?></label> <input type="text" name="dbhost" id="dbhost" placeholder="" - value="<?php p(OC_Helper::init_var('dbhost')); ?>" /> + value="<?php p($_['dbhost']); ?>" /> </p> </div> <?php endif; ?> diff --git a/lib/base.php b/lib/base.php index b54b2973551..f2d9251294d 100644 --- a/lib/base.php +++ b/lib/base.php @@ -691,7 +691,8 @@ class OC { // Check if ownCloud is installed or in maintenance (update) mode if (!OC_Config::getValue('installed', false)) { - require_once 'core/setup.php'; + $controller = new OC\Core\Setup\Controller(); + $controller->run($_POST); exit(); } diff --git a/lib/private/connector/sabre/objecttree.php b/lib/private/connector/sabre/objecttree.php index cd3f081f7cc..d1e179af2ec 100644 --- a/lib/private/connector/sabre/objecttree.php +++ b/lib/private/connector/sabre/objecttree.php @@ -38,7 +38,20 @@ class ObjectTree extends \Sabre_DAV_ObjectTree { return $this->rootNode; } - $info = $this->getFileView()->getFileInfo($path); + if (pathinfo($path, PATHINFO_EXTENSION) === 'part') { + // read from storage + $absPath = $this->getFileView()->getAbsolutePath($path); + list($storage, $internalPath) = Filesystem::resolvePath('/' . $absPath); + if ($storage) { + $scanner = $storage->getScanner($internalPath); + // get data directly + $info = $scanner->getData($internalPath); + } + } + else { + // read from cache + $info = $this->getFileView()->getFileInfo($path); + } if (!$info) { throw new \Sabre_DAV_Exception_NotFound('File with name ' . $path . ' could not be located'); diff --git a/lib/private/helper.php b/lib/private/helper.php index 58bee9c6300..580f81acc62 100644 --- a/lib/private/helper.php +++ b/lib/private/helper.php @@ -448,29 +448,6 @@ class OC_Helper { * */ - //FIXME: should also check for value validation (i.e. the email is an email). - public static function init_var($s, $d = "") { - $r = $d; - if (isset($_REQUEST[$s]) && !empty($_REQUEST[$s])) { - $r = OC_Util::sanitizeHTML($_REQUEST[$s]); - } - - return $r; - } - - /** - * returns "checked"-attribute if request contains selected radio element - * OR if radio element is the default one -- maybe? - * - * @param string $s Name of radio-button element name - * @param string $v Value of current radio-button element - * @param string $d Value of default radio-button element - */ - public static function init_radio($s, $v, $d) { - if ((isset($_REQUEST[$s]) && $_REQUEST[$s] == $v) || (!isset($_REQUEST[$s]) && $v == $d)) - print "checked=\"checked\" "; - } - /** * detect if a given program is found in the search PATH * @@ -831,23 +808,39 @@ class OC_Helper { * @return number of bytes representing */ public static function maxUploadFilesize($dir) { - $upload_max_filesize = OCP\Util::computerFileSize(ini_get('upload_max_filesize')); - $post_max_size = OCP\Util::computerFileSize(ini_get('post_max_size')); - $freeSpace = \OC\Files\Filesystem::free_space($dir); - if ((int)$upload_max_filesize === 0 and (int)$post_max_size === 0) { - $maxUploadFilesize = \OC\Files\SPACE_UNLIMITED; - } elseif ((int)$upload_max_filesize === 0 or (int)$post_max_size === 0) { - $maxUploadFilesize = max($upload_max_filesize, $post_max_size); //only the non 0 value counts - } else { - $maxUploadFilesize = min($upload_max_filesize, $post_max_size); - } + return min(self::freeSpace($dir), self::uploadLimit()); + } + /** + * Calculate free space left within user quota + * + * @param $dir the current folder where the user currently operates + * @return number of bytes representing + */ + public static function freeSpace($dir) { + $freeSpace = \OC\Files\Filesystem::free_space($dir); if ($freeSpace !== \OC\Files\SPACE_UNKNOWN) { $freeSpace = max($freeSpace, 0); + return $freeSpace; + } else { + return INF; + } + } - return min($maxUploadFilesize, $freeSpace); + /** + * Calculate PHP upload limit + * + * @return PHP upload file size limit + */ + public static function uploadLimit() { + $upload_max_filesize = OCP\Util::computerFileSize(ini_get('upload_max_filesize')); + $post_max_size = OCP\Util::computerFileSize(ini_get('post_max_size')); + if ((int)$upload_max_filesize === 0 and (int)$post_max_size === 0) { + return INF; + } elseif ((int)$upload_max_filesize === 0 or (int)$post_max_size === 0) { + return max($upload_max_filesize, $post_max_size); //only the non 0 value counts } else { - return $maxUploadFilesize; + return min($upload_max_filesize, $post_max_size); } } diff --git a/lib/private/log/errorhandler.php b/lib/private/log/errorhandler.php index f6c96ef8218..1dde6b507fc 100644 --- a/lib/private/log/errorhandler.php +++ b/lib/private/log/errorhandler.php @@ -19,7 +19,7 @@ class ErrorHandler { * @param string $msg * @return string */ - private static function removePassword($msg) { + protected static function removePassword($msg) { return preg_replace('/\/\/(.*):(.*)@/', '//xxx:xxx@', $msg); } diff --git a/lib/private/memcache/apc.php b/lib/private/memcache/apc.php index e995cbc526e..332bbfead00 100644 --- a/lib/private/memcache/apc.php +++ b/lib/private/memcache/apc.php @@ -9,15 +9,8 @@ namespace OC\Memcache; class APC extends Cache { - /** - * entries in APC gets namespaced to prevent collisions between owncloud instances and users - */ - protected function getNameSpace() { - return $this->prefix; - } - public function get($key) { - $result = apc_fetch($this->getNamespace() . $key, $success); + $result = apc_fetch($this->getPrefix() . $key, $success); if (!$success) { return null; } @@ -25,26 +18,22 @@ class APC extends Cache { } public function set($key, $value, $ttl = 0) { - return apc_store($this->getNamespace() . $key, $value, $ttl); + return apc_store($this->getPrefix() . $key, $value, $ttl); } public function hasKey($key) { - return apc_exists($this->getNamespace() . $key); + return apc_exists($this->getPrefix() . $key); } public function remove($key) { - return apc_delete($this->getNamespace() . $key); + return apc_delete($this->getPrefix() . $key); } public function clear($prefix = '') { - $ns = $this->getNamespace() . $prefix; - $cache = apc_cache_info('user'); - foreach ($cache['cache_list'] as $entry) { - if (strpos($entry['info'], $ns) === 0) { - apc_delete($entry['info']); - } - } - return true; + $ns = $this->getPrefix() . $prefix; + $ns = preg_quote($ns, '/'); + $iter = new \APCIterator('user', '/^' . $ns . '/'); + return apc_delete($iter); } static public function isAvailable() { diff --git a/lib/private/memcache/apcu.php b/lib/private/memcache/apcu.php index dac0f5f208a..7f780f32718 100644 --- a/lib/private/memcache/apcu.php +++ b/lib/private/memcache/apcu.php @@ -9,13 +9,6 @@ namespace OC\Memcache; class APCu extends APC { - public function clear($prefix = '') { - $ns = $this->getNamespace() . $prefix; - $ns = preg_quote($ns, '/'); - $iter = new \APCIterator('user', '/^'.$ns.'/'); - return apc_delete($iter); - } - static public function isAvailable() { if (!extension_loaded('apcu')) { return false; diff --git a/lib/private/memcache/cache.php b/lib/private/memcache/cache.php index 0ad1cc7ec03..03671b3f240 100644 --- a/lib/private/memcache/cache.php +++ b/lib/private/memcache/cache.php @@ -18,7 +18,7 @@ abstract class Cache implements \ArrayAccess { * @param string $prefix */ public function __construct($prefix = '') { - $this->prefix = \OC_Util::getInstanceId() . '/' . $prefix; + $this->prefix = $prefix; } public function getPrefix() { diff --git a/lib/private/memcache/factory.php b/lib/private/memcache/factory.php index fde7d947567..334cf9a1f0e 100644 --- a/lib/private/memcache/factory.php +++ b/lib/private/memcache/factory.php @@ -8,7 +8,21 @@ namespace OC\Memcache; -class Factory { +use \OCP\ICacheFactory; + +class Factory implements ICacheFactory { + /** + * @var string $globalPrefix + */ + private $globalPrefix; + + /** + * @param string $globalPrefix + */ + public function __construct($globalPrefix) { + $this->globalPrefix = $globalPrefix; + } + /** * get a cache instance, will return null if no backend is available * @@ -16,6 +30,7 @@ class Factory { * @return \OC\Memcache\Cache */ function create($prefix = '') { + $prefix = $this->globalPrefix . '/' . $prefix; if (XCache::isAvailable()) { return new XCache($prefix); } elseif (APCu::isAvailable()) { diff --git a/lib/private/server.php b/lib/private/server.php index 2cbd37a97d7..c9e593ec2ed 100644 --- a/lib/private/server.php +++ b/lib/private/server.php @@ -138,6 +138,10 @@ class Server extends SimpleContainer implements IServerContainer { $this->registerService('UserCache', function($c) { return new UserCache(); }); + $this->registerService('MemCacheFactory', function ($c) { + $instanceId = \OC_Util::getInstanceId(); + return new \OC\Memcache\Factory($instanceId); + }); $this->registerService('ActivityManager', function($c) { return new ActivityManager(); }); @@ -298,6 +302,15 @@ class Server extends SimpleContainer implements IServerContainer { } /** + * Returns an \OCP\CacheFactory instance + * + * @return \OCP\CacheFactory + */ + function getMemCacheFactory() { + return $this->query('MemCacheFactory'); + } + + /** * Returns the current session * * @return \OCP\ISession diff --git a/lib/private/util.php b/lib/private/util.php index 8aa7a074d0d..0585749d615 100755 --- a/lib/private/util.php +++ b/lib/private/util.php @@ -788,8 +788,12 @@ class OC_Util { } $fp = @fopen($testFile, 'w'); - @fwrite($fp, $testContent); - @fclose($fp); + if (!$fp) { + throw new OC\HintException('Can\'t create test file to check for working .htaccess file.', + 'Make sure it is possible for the webserver to write to '.$testFile); + } + fwrite($fp, $testContent); + fclose($fp); // accessing the file via http $url = OC_Helper::makeURLAbsolute(OC::$WEBROOT.'/data'.$fileName); diff --git a/lib/public/icachefactory.php b/lib/public/icachefactory.php new file mode 100644 index 00000000000..874f1ec0a59 --- /dev/null +++ b/lib/public/icachefactory.php @@ -0,0 +1,28 @@ +<?php +/** + * Copyright (c) 2014 Robin Appelman <icewind@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OCP; + +interface ICacheFactory{ + /** + * Get a memory cache instance + * + * All entries added trough the cache instance will be namespaced by $prefix to prevent collisions between apps + * + * @param string $prefix + * @return \OCP\ICache + */ + public function create($prefix = ''); + + /** + * Check if any memory cache backend is available + * + * @return bool + */ + public function isAvailable(); +} diff --git a/lib/public/iservercontainer.php b/lib/public/iservercontainer.php index b958d2d03f4..5473f3ee334 100644 --- a/lib/public/iservercontainer.php +++ b/lib/public/iservercontainer.php @@ -142,6 +142,13 @@ interface IServerContainer { function getCache(); /** + * Returns an \OCP\CacheFactory instance + * + * @return \OCP\ICacheFactory + */ + function getMemCacheFactory(); + + /** * Returns the current session * * @return \OCP\ISession diff --git a/lib/public/util.php b/lib/public/util.php index 26c5a15cff2..d8497e29cfc 100644 --- a/lib/public/util.php +++ b/lib/public/util.php @@ -466,4 +466,23 @@ class Util { public static function maxUploadFilesize($dir) { return \OC_Helper::maxUploadFilesize($dir); } + + /** + * Calculate free space left within user quota + * + * @param $dir the current folder where the user currently operates + * @return number of bytes representing + */ + public static function freeSpace($dir) { + return \OC_Helper::freeSpace($dir); + } + + /** + * Calculate PHP upload limit + * + * @return number of bytes representing + */ + public static function uploadLimit() { + return \OC_Helper::uploadLimit(); + } } diff --git a/tests/karma.config.js b/tests/karma.config.js index f73ade0f3c6..529bd31338f 100644 --- a/tests/karma.config.js +++ b/tests/karma.config.js @@ -29,25 +29,52 @@ * environment variable to the apps name, for example "core" or "files_encryption". * Multiple apps can be specified by separating them with space. * + * Setting the environment variable NOCOVERAGE to 1 will disable the coverage + * preprocessor, which is needed to be able to debug tests properly in a browser. */ + +/* jshint node: true */ module.exports = function(config) { + function findApps() { + /* + var fs = require('fs'); + var apps = fs.readdirSync('apps'); + return apps; + */ + // other apps tests don't run yet... needs further research / clean up + return ['files']; + } + + // respect NOCOVERAGE env variable + // it is useful to disable coverage for debugging + // because the coverage preprocessor will wrap the JS files somehow + var enableCoverage = !parseInt(process.env.NOCOVERAGE, 10); + console.log('Coverage preprocessor: ', enableCoverage?'enabled':'disabled'); + // default apps to test when none is specified (TODO: read from filesystem ?) - var defaultApps = 'core files'; - var appsToTest = process.env.KARMA_TESTSUITE || defaultApps; + var appsToTest = process.env.KARMA_TESTSUITE; + if (appsToTest) { + appsToTest = appsToTest.split(' '); + } + else { + appsToTest = ['core'].concat(findApps()); + } + + console.log('Apps to test: ', appsToTest); // read core files from core.json, // these are required by all apps so always need to be loaded // note that the loading order is important that's why they // are specified in a separate file var corePath = 'core/js/'; - var coreFiles = require('../' + corePath + 'core.json').modules; + var coreModule = require('../' + corePath + 'core.json'); var testCore = false; var files = []; var index; + var preprocessors = {}; // find out what apps to test from appsToTest - appsToTest = appsToTest.split(' '); index = appsToTest.indexOf('core'); if (index > -1) { appsToTest.splice(index, 1); @@ -60,11 +87,23 @@ module.exports = function(config) { // core mocks files.push(corePath + 'tests/specHelper.js'); - // add core files - for ( var i = 0; i < coreFiles.length; i++ ) { - files.push( corePath + coreFiles[i] ); + // add core library files + for ( var i = 0; i < coreModule.libraries.length; i++ ) { + var srcFile = corePath + coreModule.libraries[i]; + files.push(srcFile); + } + + // add core modules files + for ( var i = 0; i < coreModule.modules.length; i++ ) { + var srcFile = corePath + coreModule.modules[i]; + files.push(srcFile); + if (enableCoverage) { + preprocessors[srcFile] = 'coverage'; + } } + // TODO: settings pages + // need to test the core app as well ? if (testCore) { // core tests @@ -73,7 +112,11 @@ module.exports = function(config) { for ( var i = 0; i < appsToTest.length; i++ ) { // add app JS - files.push('apps/' + appsToTest[i] + '/js/*.js'); + var srcFile = 'apps/' + appsToTest[i] + '/js/*.js'; + files.push(srcFile); + if (enableCoverage) { + preprocessors[srcFile] = 'coverage'; + } // add test specs files.push('apps/' + appsToTest[i] + '/tests/js/*.js'); } @@ -83,7 +126,6 @@ module.exports = function(config) { // base path, that will be used to resolve files and exclude basePath: '..', - // frameworks to use frameworks: ['jasmine'], @@ -106,9 +148,7 @@ module.exports = function(config) { // web server port port: 9876, - preprocessors: { - 'apps/files/js/*.js': 'coverage' - }, + preprocessors: preprocessors, coverageReporter: { dir:'tests/karma-coverage', diff --git a/tests/lib/errorHandler.php b/tests/lib/errorHandler.php new file mode 100644 index 00000000000..68b87deccb6 --- /dev/null +++ b/tests/lib/errorHandler.php @@ -0,0 +1,62 @@ +<?php +/** + * ownCloud + * + * @author Bjoern Schiessle + * @copyright 2014 Bjoern Schiessle <schiessle@owncloud.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE + * License as published by the Free Software Foundation; either + * version 3 of the License, or any later version. + * + * This library 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 library. If not, see <http://www.gnu.org/licenses/>. + * + */ + +class Test_ErrorHandler extends \PHPUnit_Framework_TestCase { + + /** + * @brief provide username, password combinations for testRemovePassword + * @return array + */ + function passwordProvider() { + return array( + array('user', 'password'), + array('user@owncloud.org', 'password'), + array('user', 'pass@word'), + array('us:er', 'password'), + array('user', 'pass:word'), + ); + + } + + /** + * @dataProvider passwordProvider + * @param string $username + * @param string $password + */ + function testRemovePassword($username, $password) { + $url = 'http://'.$username.':'.$password.'@owncloud.org'; + $expectedResult = 'http://xxx:xxx@owncloud.org'; + $result = TestableErrorHandler::testRemovePassword($url); + + $this->assertEquals($expectedResult, $result); + } + +} + +/** + * @brief dummy class to access protected methods of \OC\Log\ErrorHandler + */ +class TestableErrorHandler extends \OC\Log\ErrorHandler { + public static function testRemovePassword($msg) { + return self::removePassword($msg); + } +} |