diff options
59 files changed, 635 insertions, 144 deletions
diff --git a/apps/files/appinfo/update.php b/apps/files/appinfo/update.php deleted file mode 100644 index de635e5ce6b..00000000000 --- a/apps/files/appinfo/update.php +++ /dev/null @@ -1,8 +0,0 @@ -<?php - -// this drops the keys below, because they aren't needed anymore -// core related -if (version_compare(\OCP\Config::getSystemValue('version', '0.0.0'), '7.0.0', '<')) { - \OCP\Config::deleteSystemValue('allowZipDownload'); - \OCP\Config::deleteSystemValue('maxZipInputSize'); -} diff --git a/apps/files/js/file-upload.js b/apps/files/js/file-upload.js index c8b3a150caa..8b0753fc647 100644 --- a/apps/files/js/file-upload.js +++ b/apps/files/js/file-upload.js @@ -501,6 +501,21 @@ OC.Upload = { } }); + } else { + // for all browsers that don't support the progress bar + // IE 8 & 9 + + // show a spinner + fileupload.on('fileuploadstart', function() { + $('#upload').addClass('icon-loading'); + $('#upload .icon-upload').hide(); + }); + + // hide a spinner + fileupload.on('fileuploadstop fileuploadfail', function() { + $('#upload').removeClass('icon-loading'); + $('#upload .icon-upload').show(); + }); } } diff --git a/apps/files/tests/ajax_rename.php b/apps/files/tests/ajax_rename.php index 48aed05823b..1cfecf9e58c 100644 --- a/apps/files/tests/ajax_rename.php +++ b/apps/files/tests/ajax_rename.php @@ -107,7 +107,7 @@ class Test_OC_Files_App_Rename extends \Test\TestCase { 'etag' => 'abcdef', 'directory' => '/', 'name' => 'new_name', - )))); + ), null))); $result = $this->files->rename($dir, $oldname, $newname); diff --git a/apps/files/tests/helper.php b/apps/files/tests/helper.php index 1b7c8eef43a..ea96e41d1d1 100644 --- a/apps/files/tests/helper.php +++ b/apps/files/tests/helper.php @@ -24,7 +24,8 @@ class Test_Files_Helper extends \Test\TestCase { 'mtime' => $mtime, 'type' => $isDir ? 'dir' : 'file', 'mimetype' => $isDir ? 'httpd/unix-directory' : 'application/octet-stream' - ) + ), + null ); } diff --git a/apps/files/tests/js/filelistSpec.js b/apps/files/tests/js/filelistSpec.js index 6c83f214c39..6dafa262715 100644 --- a/apps/files/tests/js/filelistSpec.js +++ b/apps/files/tests/js/filelistSpec.js @@ -275,7 +275,7 @@ describe('OCA.Files.FileList tests', function() { mtime: -1 }; var $tr = fileList.add(fileData); - expect($tr.find('.date').text()).toEqual('?'); + expect($tr.find('.date .modified').text()).toEqual('?'); }); it('adds new file to the end of the list', function() { var $tr; diff --git a/apps/files_encryption/lib/helper.php b/apps/files_encryption/lib/helper.php index 6a8ea25d44e..b9d45f67363 100644 --- a/apps/files_encryption/lib/helper.php +++ b/apps/files_encryption/lib/helper.php @@ -427,7 +427,7 @@ class Helper { */ public static function getOpenSSLConfig() { $config = array('private_key_bits' => 4096); - $config = array_merge(\OCP\Config::getSystemValue('openssl', array()), $config); + $config = array_merge(\OC::$server->getConfig()->getSystemValue('openssl', array()), $config); return $config; } @@ -460,7 +460,7 @@ class Helper { */ public static function getCipher() { - $cipher = \OCP\Config::getSystemValue('cipher', Crypt::DEFAULT_CIPHER); + $cipher = \OC::$server->getConfig()->getSystemValue('cipher', Crypt::DEFAULT_CIPHER); if ($cipher !== 'AES-256-CFB' && $cipher !== 'AES-128-CFB') { \OCP\Util::writeLog('files_encryption', diff --git a/apps/files_encryption/tests/crypt.php b/apps/files_encryption/tests/crypt.php index 451fa62fe57..3165279c558 100755 --- a/apps/files_encryption/tests/crypt.php +++ b/apps/files_encryption/tests/crypt.php @@ -30,6 +30,9 @@ class Crypt extends TestCase { public $genPrivateKey; public $genPublicKey; + /** @var \OCP\IConfig */ + private $config; + public static function setUpBeforeClass() { parent::setUpBeforeClass(); @@ -65,6 +68,8 @@ class Crypt extends TestCase { // we don't want to tests with app files_trashbin enabled \OC_App::disable('files_trashbin'); + + $this->config = \OC::$server->getConfig(); } protected function tearDown() { @@ -76,7 +81,7 @@ class Crypt extends TestCase { } $this->assertTrue(\OC_FileProxy::$enabled); - \OCP\Config::deleteSystemValue('cipher'); + $this->config->deleteSystemValue('cipher'); parent::tearDown(); } @@ -198,14 +203,14 @@ class Crypt extends TestCase { $filename = 'tmp-' . $this->getUniqueID() . '.test'; - \OCP\Config::setSystemValue('cipher', 'AES-128-CFB'); + $this->config->setSystemValue('cipher', 'AES-128-CFB'); $cryptedFile = file_put_contents('crypt:///' . $this->userId . '/files/'. $filename, $this->dataShort); // Test that data was successfully written $this->assertTrue(is_int($cryptedFile)); - \OCP\Config::deleteSystemValue('cipher'); + $this->config->deleteSystemValue('cipher'); // Disable encryption proxy to prevent recursive calls $proxyStatus = \OC_FileProxy::$enabled; @@ -282,7 +287,7 @@ class Crypt extends TestCase { // Generate a a random filename $filename = 'tmp-' . $this->getUniqueID() . '.test'; - \OCP\Config::setSystemValue('cipher', 'AES-128-CFB'); + $this->config->setSystemValue('cipher', 'AES-128-CFB'); // Save long data as encrypted file using stream wrapper $cryptedFile = file_put_contents('crypt:///' . $this->userId . '/files/' . $filename, $this->dataLong . $this->dataLong); @@ -294,7 +299,7 @@ class Crypt extends TestCase { $proxyStatus = \OC_FileProxy::$enabled; \OC_FileProxy::$enabled = false; - \OCP\Config::deleteSystemValue('cipher'); + $this->config->deleteSystemValue('cipher'); // Get file contents without using any wrapper to get it's actual contents on disk $retreivedCryptedFile = $this->view->file_get_contents($this->userId . '/files/' . $filename); @@ -326,12 +331,12 @@ class Crypt extends TestCase { // Generate a a random filename $filename = 'tmp-' . $this->getUniqueID() . '.test'; - \OCP\Config::setSystemValue('cipher', 'AES-128-CFB'); + $this->config->setSystemValue('cipher', 'AES-128-CFB'); // Save long data as encrypted file using stream wrapper $cryptedFile = file_put_contents('crypt:///' . $this->userId . '/files/' . $filename, $this->dataLong . $this->dataLong); - \OCP\Config::deleteSystemValue('cipher'); + $this->config->deleteSystemValue('cipher'); // Test that data was successfully written $this->assertTrue(is_int($cryptedFile)); diff --git a/apps/files_external/lib/config.php b/apps/files_external/lib/config.php index f09b29a522b..823c0bcbfc1 100644 --- a/apps/files_external/lib/config.php +++ b/apps/files_external/lib/config.php @@ -862,7 +862,7 @@ class OC_Mount_Config { include('Crypt/AES.php'); } $cipher = new Crypt_AES(CRYPT_AES_MODE_CBC); - $cipher->setKey(\OCP\Config::getSystemValue('passwordsalt')); + $cipher->setKey(\OC::$server->getConfig()->getSystemValue('passwordsalt', null)); return $cipher; } diff --git a/apps/files_external/lib/config/configadapter.php b/apps/files_external/lib/config/configadapter.php index 6294e27a774..de484a44698 100644 --- a/apps/files_external/lib/config/configadapter.php +++ b/apps/files_external/lib/config/configadapter.php @@ -33,10 +33,11 @@ class ConfigAdapter implements IMountProvider { $objectClass = $options['options']['objectstore']['class']; $options['options']['objectstore'] = new $objectClass($options['options']['objectstore']); } + $mountOptions = isset($options['mountOptions']) ? $options['mountOptions'] : []; if (isset($options['personal']) && $options['personal']) { - $mounts[] = new PersonalMount($options['class'], $mountPoint, $options['options'], $loader); + $mounts[] = new PersonalMount($options['class'], $mountPoint, $options['options'], $loader, $mountOptions); } else { - $mounts[] = new MountPoint($options['class'], $mountPoint, $options['options'], $loader); + $mounts[] = new MountPoint($options['class'], $mountPoint, $options['options'], $loader, $mountOptions); } } return $mounts; diff --git a/apps/files_external/lib/sftp.php b/apps/files_external/lib/sftp.php index f0a6f145422..f6c56669734 100644 --- a/apps/files_external/lib/sftp.php +++ b/apps/files_external/lib/sftp.php @@ -112,7 +112,7 @@ class SFTP extends \OC\Files\Storage\Common { try { $storage_view = \OCP\Files::getStorage('files_external'); if ($storage_view) { - return \OCP\Config::getSystemValue('datadirectory') . + return \OC::$server->getConfig()->getSystemValue('datadirectory') . $storage_view->getAbsolutePath('') . 'ssh_hostKeys'; } diff --git a/apps/files_external/templates/settings.php b/apps/files_external/templates/settings.php index 072f856dfbd..79950f30385 100644 --- a/apps/files_external/templates/settings.php +++ b/apps/files_external/templates/settings.php @@ -76,7 +76,7 @@ <?php endif; ?> <?php endif; ?> <?php endforeach; ?> - <?php if (isset($_['backends'][$mount['class']]['custom']) && !in_array('files_external/js/'.$_['backends'][$mount['class']]['custom'], \OC_Util::$scripts)): ?> + <?php if (isset($_['backends'][$mount['class']]['custom'])): ?> <?php OCP\Util::addScript('files_external', $_['backends'][$mount['class']]['custom']); ?> <?php endif; ?> <?php endif; ?> diff --git a/apps/files_external/tests/js/mountsfilelistSpec.js b/apps/files_external/tests/js/mountsfilelistSpec.js index 50603081b6a..a4e4fec1177 100644 --- a/apps/files_external/tests/js/mountsfilelistSpec.js +++ b/apps/files_external/tests/js/mountsfilelistSpec.js @@ -144,7 +144,7 @@ describe('OCA.External.FileList tests', function() { '?dir=/mount%20points/smb%20mount' ); expect($tr.find('.nametext').text().trim()).toEqual('smb mount'); - expect($tr.find('.column-scope').text().trim()).toEqual('Personal'); + expect($tr.find('.column-scope > span').text().trim()).toEqual('Personal'); expect($tr.find('.column-backend').text().trim()).toEqual('SMB'); }); diff --git a/apps/files_sharing/lib/external/storage.php b/apps/files_sharing/lib/external/storage.php index 3f1d631a35f..306a7b8db8a 100644 --- a/apps/files_sharing/lib/external/storage.php +++ b/apps/files_sharing/lib/external/storage.php @@ -167,6 +167,14 @@ class Storage extends DAV implements ISharedStorage { } } + public function file_exists($path) { + if ($path === '') { + return true; + } else { + return parent::file_exists($path); + } + } + /** * check if the configured remote is a valid ownCloud instance * diff --git a/apps/files_sharing/lib/helper.php b/apps/files_sharing/lib/helper.php index c83debe952f..71519bd1d4a 100644 --- a/apps/files_sharing/lib/helper.php +++ b/apps/files_sharing/lib/helper.php @@ -280,7 +280,7 @@ class Helper { * @return string */ public static function getShareFolder() { - $shareFolder = \OCP\Config::getSystemValue('share_folder', '/'); + $shareFolder = \OC::$server->getConfig()->getSystemValue('share_folder', '/'); return \OC\Files\Filesystem::normalizePath($shareFolder); } @@ -291,7 +291,7 @@ class Helper { * @param string $shareFolder */ public static function setShareFolder($shareFolder) { - \OCP\Config::setSystemValue('share_folder', $shareFolder); + \OC::$server->getConfig()->setSystemValue('share_folder', $shareFolder); } } diff --git a/apps/files_sharing/tests/api.php b/apps/files_sharing/tests/api.php index dd6de15010f..278e7130199 100644 --- a/apps/files_sharing/tests/api.php +++ b/apps/files_sharing/tests/api.php @@ -948,10 +948,11 @@ class Test_Files_Sharing_Api extends TestCase { function testUpdateShareExpireDate() { $fileInfo = $this->view->getFileInfo($this->folder); + $config = \OC::$server->getConfig(); // enforce expire date, by default 7 days after the file was shared - \OCP\Config::setAppValue('core', 'shareapi_default_expire_date', 'yes'); - \OCP\Config::setAppValue('core', 'shareapi_enforce_expire_date', 'yes'); + $config->setAppValue('core', 'shareapi_default_expire_date', 'yes'); + $config->setAppValue('core', 'shareapi_enforce_expire_date', 'yes'); $dateWithinRange = new \DateTime(); $dateWithinRange->add(new \DateInterval('P5D')); @@ -1008,8 +1009,8 @@ class Test_Files_Sharing_Api extends TestCase { $this->assertEquals($dateWithinRange->format('Y-m-d') . ' 00:00:00', $updatedLinkShare['expiration']); // cleanup - \OCP\Config::setAppValue('core', 'shareapi_default_expire_date', 'no'); - \OCP\Config::setAppValue('core', 'shareapi_enforce_expire_date', 'no'); + $config->setAppValue('core', 'shareapi_default_expire_date', 'no'); + $config->setAppValue('core', 'shareapi_enforce_expire_date', 'no'); \OCP\Share::unshare('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_LINK, null); } diff --git a/apps/files_sharing/tests/helper.php b/apps/files_sharing/tests/helper.php index 1a27739ec34..a9245ddafe5 100644 --- a/apps/files_sharing/tests/helper.php +++ b/apps/files_sharing/tests/helper.php @@ -35,7 +35,7 @@ class Test_Files_Sharing_Helper extends TestCase { $this->assertSame('/Shared', \OCA\Files_Sharing\Helper::getShareFolder()); // cleanup - \OCP\Config::deleteSystemValue('share_folder'); + \OC::$server->getConfig()->deleteSystemValue('share_folder'); } diff --git a/apps/files_sharing/tests/share.php b/apps/files_sharing/tests/share.php index f76f92734d0..83ef17f49d1 100644 --- a/apps/files_sharing/tests/share.php +++ b/apps/files_sharing/tests/share.php @@ -243,7 +243,7 @@ class Test_Files_Sharing extends OCA\Files_sharing\Tests\TestCase { $this->assertTrue(\OC\Files\Filesystem::file_exists('/Shared/subfolder/' . $this->folder)); //cleanup - \OCP\Config::deleteSystemValue('share_folder'); + \OC::$server->getConfig()->deleteSystemValue('share_folder'); } /** diff --git a/apps/files_trashbin/lib/helper.php b/apps/files_trashbin/lib/helper.php index c99662480df..d9e69b71aa0 100644 --- a/apps/files_trashbin/lib/helper.php +++ b/apps/files_trashbin/lib/helper.php @@ -31,8 +31,10 @@ class Helper return $result; } - list($storage, $internalPath) = $view->resolvePath($dir); + $mount = $view->getMount($dir); + $storage = $mount->getStorage(); $absoluteDir = $view->getAbsolutePath($dir); + $internalPath = $mount->getInternalPath($absoluteDir); if (is_resource($dirContent)) { $originalLocations = \OCA\Files_Trashbin\Trashbin::getLocations($user); @@ -65,7 +67,7 @@ class Helper if ($originalPath) { $i['extraData'] = $originalPath.'/'.$id; } - $result[] = new FileInfo($absoluteDir . '/' . $i['name'], $storage, $internalPath . '/' . $i['name'], $i); + $result[] = new FileInfo($absoluteDir . '/' . $i['name'], $storage, $internalPath . '/' . $i['name'], $i, $mount); } } closedir($dirContent); diff --git a/apps/files_trashbin/lib/trashbin.php b/apps/files_trashbin/lib/trashbin.php index 1e8f31dbd2a..952af56bacc 100644 --- a/apps/files_trashbin/lib/trashbin.php +++ b/apps/files_trashbin/lib/trashbin.php @@ -874,7 +874,7 @@ class Trashbin { * @return integer size of the folder */ private static function calculateSize($view) { - $root = \OCP\Config::getSystemValue('datadirectory') . $view->getAbsolutePath(''); + $root = \OC::$server->getConfig()->getSystemValue('datadirectory') . $view->getAbsolutePath(''); if (!file_exists($root)) { return 0; } diff --git a/apps/user_ldap/appinfo/update.php b/apps/user_ldap/appinfo/update.php index 5fad23de4f6..9bf0ca4ab53 100644 --- a/apps/user_ldap/appinfo/update.php +++ b/apps/user_ldap/appinfo/update.php @@ -1,13 +1,15 @@ <?php +$configInstance = \OC::$server->getConfig(); + //detect if we can switch on naming guidelines. We won't do it on conflicts. //it's a bit spaghetti, but hey. -$state = OCP\Config::getSystemValue('ldapIgnoreNamingRules', 'unset'); +$state = $configInstance->getSystemValue('ldapIgnoreNamingRules', 'unset'); if($state === 'unset') { - OCP\Config::setSystemValue('ldapIgnoreNamingRules', false); + $configInstance->setSystemValue('ldapIgnoreNamingRules', false); } -$installedVersion = OCP\Config::getAppValue('user_ldap', 'installed_version'); +$installedVersion = $configInstance->getAppValue('user_ldap', 'installed_version'); $enableRawMode = version_compare($installedVersion, '0.4.1', '<'); $configPrefixes = OCA\user_ldap\lib\Helper::getServerConfigurationPrefixes(true); @@ -15,31 +17,31 @@ $ldap = new OCA\user_ldap\lib\LDAP(); foreach($configPrefixes as $config) { $connection = new OCA\user_ldap\lib\Connection($ldap, $config); - $state = \OCP\Config::getAppValue( + $state = $configInstance->getAppValue( 'user_ldap', $config.'ldap_uuid_user_attribute', 'not existing'); if($state === 'non existing') { - $value = \OCP\Config::getAppValue( + $value = $configInstance->getAppValue( 'user_ldap', $config.'ldap_uuid_attribute', ''); - \OCP\Config::setAppValue( + $configInstance->setAppValue( 'user_ldap', $config.'ldap_uuid_user_attribute', $value); - \OCP\Config::setAppValue( + $configInstance->setAppValue( 'user_ldap', $config.'ldap_uuid_group_attribute', $value); } - $state = \OCP\Config::getAppValue( + $state = $configInstance->getAppValue( 'user_ldap', $config.'ldap_expert_uuid_user_attr', 'not existing'); if($state === 'non existing') { - $value = \OCP\Config::getAppValue( + $value = $configInstance->getAppValue( 'user_ldap', $config.'ldap_expert_uuid_attr', ''); - \OCP\Config::setAppValue( + $configInstance->setAppValue( 'user_ldap', $config.'ldap_expert_uuid_user_attr', $value); - \OCP\Config::setAppValue( + $configInstance->setAppValue( 'user_ldap', $config.'ldap_expert_uuid_group_attr', $value); } if($enableRawMode) { - \OCP\Config::setAppValue('user_ldap', $config.'ldap_user_filter_mode', 1); - \OCP\Config::setAppValue('user_ldap', $config.'ldap_login_filter_mode', 1); - \OCP\Config::setAppValue('user_ldap', $config.'ldap_group_filter_mode', 1); + $configInstance->setAppValue('user_ldap', $config.'ldap_user_filter_mode', 1); + $configInstance->setAppValue('user_ldap', $config.'ldap_login_filter_mode', 1); + $configInstance->setAppValue('user_ldap', $config.'ldap_group_filter_mode', 1); } } diff --git a/apps/user_ldap/lib/access.php b/apps/user_ldap/lib/access.php index 76747be70cf..22510302061 100644 --- a/apps/user_ldap/lib/access.php +++ b/apps/user_ldap/lib/access.php @@ -673,7 +673,7 @@ class Access extends LDAPUtility implements user\IUserTools { $table = $this->getMapTable($isUser); $sqlAdjustment = ''; - $dbType = \OCP\Config::getSystemValue('dbtype'); + $dbType = \OC::$server->getConfig()->getSystemValue('dbtype', null); if($dbType === 'mysql' || $dbType == 'oci') { $sqlAdjustment = 'FROM DUAL'; } diff --git a/apps/user_ldap/user_ldap.php b/apps/user_ldap/user_ldap.php index 52278082312..6c7db662ffb 100644 --- a/apps/user_ldap/user_ldap.php +++ b/apps/user_ldap/user_ldap.php @@ -199,7 +199,7 @@ class USER_LDAP extends BackendUtility implements \OCP\UserInterface { ) { $homedir = $path; } else { - $homedir = \OCP\Config::getSystemValue('datadirectory', + $homedir = \OC::$server->getConfig()->getSystemValue('datadirectory', \OC::$SERVERROOT.'/data' ) . '/' . $homedir[0]; } $this->access->connection->writeToCache($cacheKey, $homedir); diff --git a/config/config.sample.php b/config/config.sample.php index 791ffa3df90..35e3f6ce5f1 100644 --- a/config/config.sample.php +++ b/config/config.sample.php @@ -749,9 +749,21 @@ $CONFIG = array( */ 'cipher' => 'AES-256-CFB', + +/** + * Connection details for redis to use for memory caching. + * Redis is only used if other memory cache options (xcache, apc, apcu) are + * not available. + */ +'redis' => array( + 'host' => 'localhost', // can also be a unix domain socket: '/tmp/redis.sock' + 'port' => 6379, + 'timeout' => 0.0 +), + /** * Server details for one or more memcached servers to use for memory caching. - * Memcache is only used if other memory cache options (xcache, apc, apcu) are + * Memcache is only used if other memory cache options (xcache, apc, apcu, redis) are * not available. */ 'memcached_servers' => array( diff --git a/core/js/installation.js b/core/js/installation.js new file mode 100644 index 00000000000..20ff346215f --- /dev/null +++ b/core/js/installation.js @@ -0,0 +1,5 @@ + +$(document).ready(function() { + $('#adminpass').showPassword().keyup(); + $('#dbpass').showPassword().keyup(); +}); diff --git a/core/js/js.js b/core/js/js.js index f01c0eb77c1..57ce1ab6955 100644 --- a/core/js/js.js +++ b/core/js/js.js @@ -1081,35 +1081,6 @@ function initCore() { } }); - var setShowPassword = function(input, label) { - input.showPassword().keyup(); - }; - setShowPassword($('#adminpass'), $('label[for=show]')); - setShowPassword($('#pass2'), $('label[for=personal-show]')); - setShowPassword($('#dbpass'), $('label[for=dbpassword]')); - - var checkShowCredentials = function() { - var empty = false; - $('input#user, input#password').each(function() { - if ($(this).val() === '') { - empty = true; - } - }); - if(empty) { - $('#submit').fadeOut(); - $('#remember_login').hide(); - $('#remember_login+label').fadeOut(); - } else { - $('#submit').fadeIn(); - $('#remember_login').show(); - $('#remember_login+label').fadeIn(); - } - }; - // hide log in button etc. when form fields not filled - // commented out due to some browsers having issues with it - // checkShowCredentials(); - // $('input#user, input#password').keyup(checkShowCredentials); - // user menu $('#settings #expand').keydown(function(event) { if (event.which === 13 || event.which === 32) { diff --git a/core/templates/installation.php b/core/templates/installation.php index 9ef63dbfe8c..0b3b0d46c5c 100644 --- a/core/templates/installation.php +++ b/core/templates/installation.php @@ -1,3 +1,9 @@ +<?php +script('core', [ + 'jquery-showpassword', + 'installation' +]); +?> <input type='hidden' id='hasMySQL' value='<?php p($_['hasMySQL']) ?>'> <input type='hidden' id='hasSQLite' value='<?php p($_['hasSQLite']) ?>'> <input type='hidden' id='hasPostgreSQL' value='<?php p($_['hasPostgreSQL']) ?>'> diff --git a/core/templates/login.php b/core/templates/login.php index 86a1b605df5..2198f063dbc 100644 --- a/core/templates/login.php +++ b/core/templates/login.php @@ -1,5 +1,11 @@ <?php /** @var $l OC_L10N */ ?> -<?php vendor_script('jsTimezoneDetect/jstz') ?> +<?php +vendor_script('jsTimezoneDetect/jstz'); +script('core', [ + 'visitortimezone', + 'lostpassword' +]); +?> <!--[if IE 8]><style>input[type="checkbox"]{padding:0;}</style><![endif]--> <form method="post" name="login"> @@ -65,8 +71,5 @@ </ul> </fieldset> </form> -<?php } ?> +<?php } -<?php -OCP\Util::addscript('core', 'visitortimezone'); -OCP\Util::addScript('core', 'lostpassword'); diff --git a/lib/base.php b/lib/base.php index ae87ecff394..009732ead7b 100644 --- a/lib/base.php +++ b/lib/base.php @@ -336,7 +336,6 @@ class OC { public static function initTemplateEngine() { // Add the stuff we need always - // following logic will import all vendor libraries that are // specified in core/js/core.json $fileContent = file_get_contents(OC::$SERVERROOT . '/core/js/core.json'); @@ -351,7 +350,6 @@ class OC { throw new \Exception('Cannot read core/js/core.json'); } - OC_Util::addScript("jquery-showpassword"); OC_Util::addScript("placeholders"); OC_Util::addScript("jquery-tipsy"); OC_Util::addScript("compatibility"); diff --git a/lib/private/connector/sabre/directory.php b/lib/private/connector/sabre/directory.php index ec5f82f9daa..bbe0f3452a7 100644 --- a/lib/private/connector/sabre/directory.php +++ b/lib/private/connector/sabre/directory.php @@ -72,7 +72,7 @@ class OC_Connector_Sabre_Directory extends OC_Connector_Sabre_Node $path = $this->fileView->getAbsolutePath($this->path) . '/' . $name; // using a dummy FileInfo is acceptable here since it will be refreshed after the put is complete - $info = new \OC\Files\FileInfo($path, null, null, array()); + $info = new \OC\Files\FileInfo($path, null, null, array(), null); $node = new OC_Connector_Sabre_File($this->fileView, $info); return $node->put($data); } catch (\OCP\Files\StorageNotAvailableException $e) { diff --git a/lib/private/connector/sabre/objecttree.php b/lib/private/connector/sabre/objecttree.php index 14a55b5cada..d2759d7a3ba 100644 --- a/lib/private/connector/sabre/objecttree.php +++ b/lib/private/connector/sabre/objecttree.php @@ -71,7 +71,9 @@ class ObjectTree extends \Sabre\DAV\ObjectTree { if (pathinfo($path, PATHINFO_EXTENSION) === 'part') { // read from storage $absPath = $this->fileView->getAbsolutePath($path); - list($storage, $internalPath) = Filesystem::resolvePath('/' . $absPath); + $mount = $this->fileView->getMount($path); + $storage = $mount->getStorage(); + $internalPath = $mount->getInternalPath($absPath); if ($storage) { /** * @var \OC\Files\Storage\Storage $storage @@ -79,7 +81,7 @@ class ObjectTree extends \Sabre\DAV\ObjectTree { $scanner = $storage->getScanner($internalPath); // get data directly $data = $scanner->getData($internalPath); - $info = new FileInfo($absPath, $storage, $internalPath, $data); + $info = new FileInfo($absPath, $storage, $internalPath, $data, $mount); } else { $info = null; } diff --git a/lib/private/files/fileinfo.php b/lib/private/files/fileinfo.php index 8bab51f0737..e4a397dcca2 100644 --- a/lib/private/files/fileinfo.php +++ b/lib/private/files/fileinfo.php @@ -30,14 +30,23 @@ class FileInfo implements \OCP\Files\FileInfo, \ArrayAccess { private $internalPath; /** + * @var \OCP\Files\Mount\IMountPoint + */ + private $mount; + + /** * @param string|boolean $path * @param Storage\Storage $storage + * @param string $internalPath + * @param array $data + * @param \OCP\Files\Mount\IMountPoint $mount */ - public function __construct($path, $storage, $internalPath, $data) { + public function __construct($path, $storage, $internalPath, $data, $mount) { $this->path = $path; $this->storage = $storage; $this->internalPath = $internalPath; $this->data = $data; + $this->mount = $mount; } public function offsetSet($offset, $value) { @@ -208,6 +217,7 @@ class FileInfo implements \OCP\Files\FileInfo, \ArrayAccess { /** * Check if a file or folder is shared + * * @return bool */ public function isShared() { @@ -229,4 +239,13 @@ class FileInfo implements \OCP\Files\FileInfo, \ArrayAccess { return false; } + + /** + * Get the mountpoint the file belongs to + * + * @return \OCP\Files\Mount\IMountPoint + */ + public function getMountPoint() { + return $this->mount; + } } diff --git a/lib/private/files/mount/mountpoint.php b/lib/private/files/mount/mountpoint.php index b2c50f9d881..77a51a17020 100644 --- a/lib/private/files/mount/mountpoint.php +++ b/lib/private/files/mount/mountpoint.php @@ -20,10 +20,23 @@ class MountPoint implements IMountPoint { protected $storage = null; protected $class; protected $storageId; + + /** + * Configuration options for the storage backend + * + * @var array + */ protected $arguments = array(); protected $mountPoint; /** + * Mount specific options + * + * @var array + */ + protected $mountOptions = array(); + + /** * @var \OC\Files\Storage\StorageFactory $loader */ private $loader; @@ -31,10 +44,11 @@ class MountPoint implements IMountPoint { /** * @param string|\OC\Files\Storage\Storage $storage * @param string $mountpoint - * @param array $arguments (optional)\ + * @param array $arguments (optional) configuration for the storage backend * @param \OCP\Files\Storage\IStorageFactory $loader + * @param array $mountOptions mount specific options */ - public function __construct($storage, $mountpoint, $arguments = null, $loader = null) { + public function __construct($storage, $mountpoint, $arguments = null, $loader = null, $mountOptions = null) { if (is_null($arguments)) { $arguments = array(); } @@ -44,6 +58,10 @@ class MountPoint implements IMountPoint { $this->loader = $loader; } + if (!is_null($mountOptions)) { + $this->mountOptions = $mountOptions; + } + $mountpoint = $this->formatPath($mountpoint); if ($storage instanceof Storage) { $this->class = get_class($storage); @@ -161,4 +179,15 @@ class MountPoint implements IMountPoint { public function wrapStorage($wrapper) { $this->storage = $wrapper($this->mountPoint, $this->getStorage()); } + + /** + * Get a mount option + * + * @param string $name Name of the mount option to get + * @param mixed $default Default value for the mount option + * @return mixed + */ + public function getOption($name, $default) { + return isset($this->mountOptions[$name]) ? $this->mountOptions[$name] : $default; + } } diff --git a/lib/private/files/node/node.php b/lib/private/files/node/node.php index 87d4a4b9156..17907a53044 100644 --- a/lib/private/files/node/node.php +++ b/lib/private/files/node/node.php @@ -288,4 +288,8 @@ class Node implements \OCP\Files\Node, FileInfo { public function isEncrypted() { return $this->getFileInfo()->isEncrypted(); } + + public function getMountPoint() { + return $this->getFileInfo()->getMountPoint(); + } } diff --git a/lib/private/files/view.php b/lib/private/files/view.php index c01763cdad3..f1c15e197d9 100644 --- a/lib/private/files/view.php +++ b/lib/private/files/view.php @@ -113,6 +113,19 @@ class View { } /** + * get the mountpoint of the storage object for a path + * ( note: because a storage is not always mounted inside the fakeroot, the + * returned mountpoint is relative to the absolute root of the filesystem + * and doesn't take the chroot into account ) + * + * @param string $path + * @return \OCP\Files\Mount\IMountPoint + */ + public function getMount($path) { + return Filesystem::getMountManager()->find($this->getAbsolutePath($path)); + } + + /** * resolve a path to a storage and internal path * * @param string $path @@ -280,6 +293,11 @@ class View { } public function isDeletable($path) { + $absolutePath = $this->getAbsolutePath($path); + $mount = Filesystem::getMountManager()->find($absolutePath); + if ($mount->getInternalPath($absolutePath) === '') { + return $mount instanceof MoveableMount; + } return $this->basicOperation('isDeletable', $path); } @@ -938,7 +956,7 @@ class View { $data = \OC_FileProxy::runPostProxies('getFileInfo', $path, $data); - return new FileInfo($path, $storage, $internalPath, $data); + return new FileInfo($path, $storage, $internalPath, $data, $mount); } /** @@ -955,8 +973,10 @@ class View { return $result; } $path = $this->getAbsolutePath($directory); - /** @var \OC\Files\Storage\Storage $storage */ - list($storage, $internalPath) = $this->resolvePath($directory); + $path = Filesystem::normalizePath($path); + $mount = $this->getMount($directory); + $storage = $mount->getStorage(); + $internalPath = $mount->getInternalPath($path); if ($storage) { $cache = $storage->getCache($internalPath); $user = \OC_User::getUser(); @@ -990,7 +1010,7 @@ class View { if (\OCP\Util::isSharingDisabledForUser()) { $content['permissions'] = $content['permissions'] & ~\OCP\Constants::PERMISSION_SHARE; } - $files[] = new FileInfo($path . '/' . $content['name'], $storage, $content['path'], $content); + $files[] = new FileInfo($path . '/' . $content['name'], $storage, $content['path'], $content, $mount); } //add a folder for any mountpoint in this directory and add the sizes of other mountpoints to the folders @@ -998,7 +1018,7 @@ class View { $dirLength = strlen($path); foreach ($mounts as $mount) { $mountPoint = $mount->getMountPoint(); - $subStorage = Filesystem::getStorage($mountPoint); + $subStorage = $mount->getStorage(); if ($subStorage) { $subCache = $subStorage->getCache(''); @@ -1044,7 +1064,7 @@ class View { $content['permissions'] = $content['permissions'] & ~\OCP\Constants::PERMISSION_SHARE; } - $files[] = new FileInfo($path . '/' . $rootEntry['name'], $subStorage, '', $rootEntry); + $files[] = new FileInfo($path . '/' . $rootEntry['name'], $subStorage, '', $rootEntry, $mount); } } } @@ -1154,8 +1174,9 @@ class View { $files = array(); $rootLength = strlen($this->fakeRoot); - $mountPoint = Filesystem::getMountPoint($this->fakeRoot); - $storage = Filesystem::getStorage($mountPoint); + $mount = $this->getMount(''); + $mountPoint = $mount->getMountPoint(); + $storage = $mount->getStorage(); if ($storage) { $cache = $storage->getCache(''); @@ -1165,13 +1186,14 @@ class View { $internalPath = $result['path']; $path = $mountPoint . $result['path']; $result['path'] = substr($mountPoint . $result['path'], $rootLength); - $files[] = new FileInfo($path, $storage, $internalPath, $result); + $files[] = new FileInfo($path, $storage, $internalPath, $result, $mount); } } - $mountPoints = Filesystem::getMountPoints($this->fakeRoot); - foreach ($mountPoints as $mountPoint) { - $storage = Filesystem::getStorage($mountPoint); + $mounts = Filesystem::getMountManager()->findIn($this->fakeRoot); + foreach ($mounts as $mount) { + $mountPoint = $mount->getMountPoint(); + $storage = $mount->getStorage(); if ($storage) { $cache = $storage->getCache(''); @@ -1182,7 +1204,7 @@ class View { $internalPath = $result['path']; $result['path'] = rtrim($relativeMountPoint . $result['path'], '/'); $path = rtrim($mountPoint . $internalPath, '/'); - $files[] = new FileInfo($path, $storage, $internalPath, $result); + $files[] = new FileInfo($path, $storage, $internalPath, $result, $mount); } } } diff --git a/lib/private/image.php b/lib/private/image.php index 78cacc84452..07cfb0f72d3 100644 --- a/lib/private/image.php +++ b/lib/private/image.php @@ -37,7 +37,7 @@ class OC_Image { */ static public function getMimeTypeForFile($filePath) { // exif_imagetype throws "read error!" if file is less than 12 byte - if (filesize($filePath) > 11) { + if ($filePath !== null && filesize($filePath) > 11) { $imageType = exif_imagetype($filePath); } else { $imageType = false; diff --git a/lib/private/memcache/factory.php b/lib/private/memcache/factory.php index 8e47a8899fc..dba9e8a0e00 100644 --- a/lib/private/memcache/factory.php +++ b/lib/private/memcache/factory.php @@ -37,6 +37,8 @@ class Factory implements ICacheFactory { return new APCu($prefix); } elseif (APC::isAvailable()) { return new APC($prefix); + } elseif (Redis::isAvailable()) { + return new Redis($prefix); } elseif (Memcached::isAvailable()) { return new Memcached($prefix); } else { @@ -50,7 +52,7 @@ class Factory implements ICacheFactory { * @return bool */ public function isAvailable() { - return XCache::isAvailable() || APCu::isAvailable() || APC::isAvailable() || Memcached::isAvailable(); + return XCache::isAvailable() || APCu::isAvailable() || APC::isAvailable() || Redis::isAvailable() || Memcached::isAvailable(); } /** diff --git a/lib/private/memcache/redis.php b/lib/private/memcache/redis.php new file mode 100644 index 00000000000..f21619887d0 --- /dev/null +++ b/lib/private/memcache/redis.php @@ -0,0 +1,94 @@ +<?php +/** + * Copyright (c) 2014 Jörn Friedrich Dreyer <jfd@butonic.de> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Memcache; + +class Redis extends Cache { + + /** + * @var \Redis $cache + */ + private static $cache = null; + + public function __construct($prefix = '') { + parent::__construct($prefix); + if (is_null(self::$cache)) { + // TODO allow configuring a RedisArray, see https://github.com/nicolasff/phpredis/blob/master/arrays.markdown#redis-arrays + self::$cache = new \Redis(); + $config = \OC::$server->getSystemConfig()->getValue('redis', array()); + if (isset($config['host'])) { + $host = $config['host']; + } else { + $host = '127.0.0.1'; + } + if (isset($config['port'])) { + $port = $config['port']; + } else { + $port = 6379; + } + if (isset($config['timeout'])) { + $timeout = $config['timeout']; + } else { + $timeout = 0.0; // unlimited + } + self::$cache->connect( $host, $port, $timeout ); + } + } + + /** + * entries in redis get namespaced to prevent collisions between ownCloud instances and users + */ + protected function getNameSpace() { + return $this->prefix; + } + + public function get($key) { + $result = self::$cache->get($this->getNamespace() . $key); + if ($result === false and ! self::$cache->exists($this->getNamespace() . $key)) { + return null; + } else { + return $result; + } + } + + public function set($key, $value, $ttl = 0) { + if ($ttl > 0) { + return self::$cache->setex($this->getNamespace() . $key, $ttl, $value); + } else { + return self::$cache->set($this->getNamespace() . $key, $value); + } + } + + public function hasKey($key) { + return self::$cache->exists($this->getNamespace() . $key); + } + + public function remove($key) { + if (self::$cache->delete($this->getNamespace() . $key)) { + return true; + } else { + return false; + } + + } + + public function clear($prefix = '') { + $prefix = $this->getNamespace() . $prefix.'*'; + $it = null; + self::$cache->setOption(\Redis::OPT_SCAN, \Redis::SCAN_RETRY); + while($keys = self::$cache->scan($it, $prefix)) { + self::$cache->delete($keys); + } + return true; + } + + static public function isAvailable() { + return extension_loaded('redis'); + } +} + diff --git a/lib/private/preview.php b/lib/private/preview.php index 7305bf1cc0e..a586c94fd11 100644 --- a/lib/private/preview.php +++ b/lib/private/preview.php @@ -922,6 +922,11 @@ class Preview { return false; } + $mount = $file->getMountPoint(); + if ($mount and !$mount->getOption('previews', true)){ + return false; + } + //check if there are preview backends if (empty(self::$providers)) { self::initProviders(); diff --git a/lib/private/template.php b/lib/private/template.php index bda802fd2e2..78ebb506385 100644 --- a/lib/private/template.php +++ b/lib/private/template.php @@ -122,7 +122,7 @@ class OC_Template extends \OC\Template\Base { foreach(OC_Util::$headers as $header) { $headers .= '<'.OC_Util::sanitizeHTML($header['tag']); foreach($header['attributes'] as $name=>$value) { - $headers .= ' "'.OC_Util::sanitizeHTML($name).'"="'.OC_Util::sanitizeHTML($value).'"'; + $headers .= ' '.OC_Util::sanitizeHTML($name).'="'.OC_Util::sanitizeHTML($value).'"'; } if ($header['text'] !== null) { $headers .= '>'.OC_Util::sanitizeHTML($header['text']).'</'.OC_Util::sanitizeHTML($header['tag']).'>'; diff --git a/lib/private/util.php b/lib/private/util.php index 6ccb9dba087..b97c0684629 100644 --- a/lib/private/util.php +++ b/lib/private/util.php @@ -333,9 +333,9 @@ class OC_Util { /** * generates a path for JS/CSS files. If no application is provided it will create the path for core. * - * @param $application application to get the files from - * @param $directory directory withing this application (css, js, vendor, etc) - * @param $file the file inside of the above folder + * @param string $application application to get the files from + * @param string $directory directory withing this application (css, js, vendor, etc) + * @param string $file the file inside of the above folder * @return string the path */ private static function generatePath($application, $directory, $file) { @@ -358,7 +358,10 @@ class OC_Util { * @return void */ public static function addScript($application, $file = null) { - self::$scripts[] = OC_Util::generatePath($application, 'js', $file); + $path = OC_Util::generatePath($application, 'js', $file); + if (!in_array($path, self::$scripts)) { + self::$scripts[] = $path; + } } /** @@ -369,7 +372,10 @@ class OC_Util { * @return void */ public static function addVendorScript($application, $file = null) { - self::$scripts[] = OC_Util::generatePath($application, 'vendor', $file); + $path = OC_Util::generatePath($application, 'vendor', $file); + if (!in_array($path, self::$scripts)) { + self::$scripts[] = $path; + } } /** @@ -384,9 +390,12 @@ class OC_Util { $languageCode = $l->getLanguageCode($application); } if (!empty($application)) { - self::$scripts[] = "$application/l10n/$languageCode"; + $path = "$application/l10n/$languageCode"; } else { - self::$scripts[] = "l10n/$languageCode"; + $path = "l10n/$languageCode"; + } + if (!in_array($path, self::$scripts)) { + self::$scripts[] = $path; } } @@ -398,7 +407,10 @@ class OC_Util { * @return void */ public static function addStyle($application, $file = null) { - self::$styles[] = OC_Util::generatePath($application, 'css', $file); + $path = OC_Util::generatePath($application, 'css', $file); + if (!in_array($path, self::$styles)) { + self::$styles[] = $path; + } } /** @@ -409,7 +421,10 @@ class OC_Util { * @return void */ public static function addVendorStyle($application, $file = null) { - self::$styles[] = OC_Util::generatePath($application, 'vendor', $file); + $path = OC_Util::generatePath($application, 'vendor', $file); + if (!in_array($path, self::$styles)) { + self::$styles[] = $path; + } } /** @@ -1344,4 +1359,5 @@ class OC_Util { public static function isPhpCharSetUtf8() { return ini_get('default_charset') === 'UTF-8'; } + } diff --git a/lib/public/files/fileinfo.php b/lib/public/files/fileinfo.php index 3a407ed67ca..ec68ed475c5 100644 --- a/lib/public/files/fileinfo.php +++ b/lib/public/files/fileinfo.php @@ -169,4 +169,11 @@ interface FileInfo { * @return bool */ public function isMounted(); + + /** + * Get the mountpoint the file belongs to + * + * @return \OCP\Files\Mount\IMountPoint + */ + public function getMountPoint(); } diff --git a/lib/public/files/mount/imountpoint.php b/lib/public/files/mount/imountpoint.php index dac634bae4c..af7819ae160 100644 --- a/lib/public/files/mount/imountpoint.php +++ b/lib/public/files/mount/imountpoint.php @@ -55,4 +55,13 @@ interface IMountPoint { * @param callable $wrapper */ public function wrapStorage($wrapper); + + /** + * Get a mount option + * + * @param string $name Name of the mount option to get + * @param mixed $default Default value for the mount option + * @return mixed + */ + public function getOption($name, $default); } diff --git a/settings/application.php b/settings/application.php index 0a80bd8b1e7..74d021c5bf3 100644 --- a/settings/application.php +++ b/settings/application.php @@ -83,7 +83,12 @@ class Application extends App { $c->query('UserSession'), $c->query('Config'), $c->query('IsAdmin'), - $c->query('L10N') + $c->query('L10N'), + $c->query('Logger'), + $c->query('Defaults'), + $c->query('Mail'), + $c->query('DefaultMailAddress'), + $c->query('URLGenerator') ); }); @@ -134,5 +139,11 @@ class Application extends App { $container->registerService('DefaultMailAddress', function(IContainer $c) { return Util::getDefaultEmailAddress('no-reply'); }); + $container->registerService('Logger', function(IContainer $c) { + return $c->query('ServerContainer')->getLogger(); + }); + $container->registerService('URLGenerator', function(IContainer $c) { + return $c->query('ServerContainer')->getURLGenerator(); + }); } } diff --git a/settings/controller/userscontroller.php b/settings/controller/userscontroller.php index c25989af1a9..0349a4c3d16 100644 --- a/settings/controller/userscontroller.php +++ b/settings/controller/userscontroller.php @@ -15,10 +15,13 @@ use OC\User\Manager; use OC\User\User; use \OCP\AppFramework\Controller; use OCP\AppFramework\Http\DataResponse; +use OCP\AppFramework\Http\TemplateResponse; use OCP\IConfig; use OCP\IGroupManager; use OCP\IL10N; +use OCP\ILogger; use OCP\IRequest; +use OCP\IURLGenerator; use OCP\IUser; use OCP\IUserManager; use OCP\IUserSession; @@ -39,6 +42,16 @@ class UsersController extends Controller { private $groupManager; /** @var IConfig */ private $config; + /** @var ILogger */ + private $log; + /** @var \OC_Defaults */ + private $defaults; + /** @var \OC_Mail */ + private $mail; + /** @var string */ + private $fromMailAddress; + /** @var IURLGenerator */ + private $urlGenerator; /** * @param string $appName @@ -49,6 +62,10 @@ class UsersController extends Controller { * @param IConfig $config * @param bool $isAdmin * @param IL10N $l10n + * @param ILogger $log + * @param \OC_Defaults $defaults + * @param \OC_Mail $mail + * @param string $fromMailAddress */ public function __construct($appName, IRequest $request, @@ -57,7 +74,12 @@ class UsersController extends Controller { IUserSession $userSession, IConfig $config, $isAdmin, - IL10N $l10n) { + IL10N $l10n, + ILogger $log, + \OC_Defaults $defaults, + \OC_Mail $mail, + $fromMailAddress, + IURLGenerator $urlGenerator) { parent::__construct($appName, $request); $this->userManager = $userManager; $this->groupManager = $groupManager; @@ -65,6 +87,11 @@ class UsersController extends Controller { $this->config = $config; $this->isAdmin = $isAdmin; $this->l10n = $l10n; + $this->log = $log; + $this->defaults = $defaults; + $this->mail = $mail; + $this->fromMailAddress = $fromMailAddress; + $this->urlGenerator = $urlGenerator; } /** @@ -164,12 +191,23 @@ class UsersController extends Controller { * @param string $username * @param string $password * @param array $groups + * @param string $email * @return DataResponse * * TODO: Tidy up and write unit tests - code is mainly static method calls */ - public function create($username, $password, array $groups) { + public function create($username, $password, array $groups=array(), $email='') { + if($email !== '' && !$this->mail->validateAddress($email)) { + return new DataResponse( + array( + 'message' => (string)$this->l10n->t('Invalid mail address') + ), + Http::STATUS_UNPROCESSABLE_ENTITY + ); + } + + // TODO FIXME get rid of the static calls to OC_Subadmin if (!$this->isAdmin) { if (!empty($groups)) { foreach ($groups as $key => $group) { @@ -195,13 +233,49 @@ class UsersController extends Controller { } if($user instanceof User) { - foreach( $groups as $groupName ) { - $group = $this->groupManager->get($groupName); + if($groups !== null) { + foreach( $groups as $groupName ) { + $group = $this->groupManager->get($groupName); + + if(empty($group)) { + $group = $this->groupManager->createGroup($groupName); + } + $group->addUser($user); + } + } + /** + * Send new user mail only if a mail is set + */ + if($email !== '') { + $this->config->setUserValue($username, 'settings', 'email', $email); + + // data for the mail template + $mailData = array( + 'username' => $username, + 'url' => $this->urlGenerator->getAbsoluteURL('/') + ); + + $mail = new TemplateResponse('settings', 'email.new_user', $mailData, 'blank'); + $mailContent = $mail->render(); + + $mail = new TemplateResponse('settings', 'email.new_user_plain_text', $mailData, 'blank'); + $plainTextMailContent = $mail->render(); + + $subject = $this->l10n->t('Your %s account was created', [$this->defaults->getName()]); - if(empty($group)) { - $group = $this->groupManager->createGroup($groupName); + try { + $this->mail->send( + $email, + $username, + $subject, + $mailContent, + $this->fromMailAddress, + $this->defaults->getName(), + 1, + $plainTextMailContent); + } catch(\Exception $e) { + $this->log->error("Can't send new user mail to $email: " . $e->getMessage(), array('app' => 'settings')); } - $group->addUser($user); } } diff --git a/settings/js/personal.js b/settings/js/personal.js index b2efa7c37f9..ac29f69037e 100644 --- a/settings/js/personal.js +++ b/settings/js/personal.js @@ -157,6 +157,7 @@ function avatarResponseHandler (data) { } $(document).ready(function () { + $('#pass2').showPassword().keyup(); $("#passwordbutton").click(function () { if ($('#pass1').val() !== '' && $('#pass2').val() !== '') { // Serialize the data diff --git a/settings/js/users/users.js b/settings/js/users/users.js index d910e1ec129..e0eb5ff1601 100644 --- a/settings/js/users/users.js +++ b/settings/js/users/users.js @@ -695,6 +695,7 @@ $(document).ready(function () { event.preventDefault(); var username = $('#newusername').val(); var password = $('#newuserpassword').val(); + var email = $('#newemail').val(); if ($.trim(username) === '') { OC.dialogs.alert( t('settings', 'A valid username must be provided'), @@ -707,14 +708,24 @@ $(document).ready(function () { t('settings', 'Error creating user')); return false; } - var groups = $('#newusergroups').val(); + if(!$('#CheckboxMailOnUserCreate').is(':checked')) { + email = ''; + } + if ($('#CheckboxMailOnUserCreate').is(':checked') && $.trim(email) === '') { + OC.dialogs.alert( + t('settings', 'A valid email must be provided'), + t('settings', 'Error creating user')); + return false; + } + var groups = $('#newusergroups').val() || []; $('#newuser').get(0).reset(); $.post( OC.generateUrl('/settings/users/users'), { username: username, password: password, - groups: groups + groups: groups, + email: email }, function (result) { if (result.groups) { @@ -774,6 +785,14 @@ $(document).ready(function () { $("#userlist .userBackend").hide(); } }); + // Option to display/hide the "E-Mail" input field + $('#CheckboxMailOnUserCreate').click(function() { + if ($('#CheckboxMailOnUserCreate').is(':checked')) { + $("#newemail").show(); + } else { + $("#newemail").hide(); + } + }); // calculate initial limit of users to load var initialUserCountLimit = 20, diff --git a/settings/templates/email.new_user.php b/settings/templates/email.new_user.php new file mode 100644 index 00000000000..74149632cb8 --- /dev/null +++ b/settings/templates/email.new_user.php @@ -0,0 +1,36 @@ +<table cellspacing="0" cellpadding="0" border="0" width="100%"> + <tr><td> + <table cellspacing="0" cellpadding="0" border="0" width="600px"> + <tr> + <td bgcolor="<?php p($theme->getMailHeaderColor());?>" width="20px"> </td> + <td bgcolor="<?php p($theme->getMailHeaderColor());?>"> + <img src="<?php p(OC_Helper::makeURLAbsolute(image_path('', 'logo-mail.gif'))); ?>" alt="<?php p($theme->getName()); ?>"/> + </td> + </tr> + <tr><td colspan="2"> </td></tr> + <tr> + <td width="20px"> </td> + <td style="font-weight:normal; font-size:0.8em; line-height:1.2em; font-family:verdana,'arial',sans;"> + <?php + print_unescaped($l->t('Hey there,<br><br>just letting you know that you now have an %s account.<br><br>Your username: %s<br>Access it: <a href="%s">%s</a><br><br>', array($theme->getName(), $_['username'], $_['url'], $_['url']))); + + // TRANSLATORS term at the end of a mail + p($l->t('Cheers!')); + ?> + </td> + </tr> + <tr><td colspan="2"> </td></tr> + <tr> + <td width="20px"> </td> + <td style="font-weight:normal; font-size:0.8em; line-height:1.2em; font-family:verdana,'arial',sans;">--<br> + <?php p($theme->getName()); ?> - + <?php p($theme->getSlogan()); ?> + <br><a href="<?php p($theme->getBaseUrl()); ?>"><?php p($theme->getBaseUrl());?></a> + </td> + </tr> + <tr> + <td colspan="2"> </td> + </tr> + </table> + </td></tr> +</table> diff --git a/settings/templates/email.new_user_plain_text.php b/settings/templates/email.new_user_plain_text.php new file mode 100644 index 00000000000..79559a87020 --- /dev/null +++ b/settings/templates/email.new_user_plain_text.php @@ -0,0 +1,10 @@ +<?php +print_unescaped($l->t("Hey there,\n\njust letting you know that you now have an %s account.\n\nYour username: %s\nAccess it: %s\n\n", array($theme->getName(), $_['username'], $_['url']))); + +// TRANSLATORS term at the end of a mail +p($l->t("Cheers!")); +?> + + -- +<?php p($theme->getName() . ' - ' . $theme->getSlogan()); ?> +<?php print_unescaped("\n".$theme->getBaseUrl()); diff --git a/settings/templates/personal.php b/settings/templates/personal.php index 83cf9c72f76..ad61f398b1c 100644 --- a/settings/templates/personal.php +++ b/settings/templates/personal.php @@ -66,6 +66,7 @@ <?php if($_['passwordChangeSupported']) { + script('jquery-showpassword'); ?> <form id="passwordform" class="section"> <h2><?php p($l->t('Password'));?></h2> diff --git a/settings/templates/users/main.php b/settings/templates/users/main.php index c32c8df6809..2004c10b9ac 100644 --- a/settings/templates/users/main.php +++ b/settings/templates/users/main.php @@ -62,6 +62,12 @@ translation('settings'); <?php p($l->t('Show user backend')) ?> </label> </p> + <p> + <input type="checkbox" name="MailOnUserCreate" value="MailOnUserCreate" id="CheckboxMailOnUserCreate"> + <label for="CheckboxMailOnUserCreate"> + <?php p($l->t('Send mail to new user')) ?> + </label> + </p> </div> </div> </div> diff --git a/settings/templates/users/part.createuser.php b/settings/templates/users/part.createuser.php index d3ebbfb987a..9d9886f694c 100644 --- a/settings/templates/users/part.createuser.php +++ b/settings/templates/users/part.createuser.php @@ -7,6 +7,9 @@ type="password" id="newuserpassword" placeholder="<?php p($l->t('Password'))?>" autocomplete="off" autocapitalize="off" autocorrect="off" /> + <input id="newemail" type="text" style="display:none" + placeholder="<?php p($l->t('E-Mail'))?>" + autocomplete="off" autocapitalize="off" autocorrect="off" /> <select class="groupsselect" id="newusergroups" data-placeholder="groups" title="<?php p($l->t('Groups'))?>" multiple="multiple"> diff --git a/tests/lib/connector/sabre/file.php b/tests/lib/connector/sabre/file.php index b4fdd91f512..6bb1b4e75d1 100644 --- a/tests/lib/connector/sabre/file.php +++ b/tests/lib/connector/sabre/file.php @@ -24,7 +24,7 @@ class Test_OC_Connector_Sabre_File extends \Test\TestCase { $info = new \OC\Files\FileInfo('/test.txt', null, null, array( 'permissions'=>\OCP\Constants::PERMISSION_ALL - )); + ), null); $file = new OC_Connector_Sabre_File($view, $info); @@ -59,7 +59,7 @@ class Test_OC_Connector_Sabre_File extends \Test\TestCase { $info = new \OC\Files\FileInfo('/test.txt', null, null, array( 'permissions' => \OCP\Constants::PERMISSION_ALL - )); + ), null); $file = new OC_Connector_Sabre_File($view, $info); @@ -83,7 +83,7 @@ class Test_OC_Connector_Sabre_File extends \Test\TestCase { $info = new \OC\Files\FileInfo('/super*star.txt', null, null, array( 'permissions' => \OCP\Constants::PERMISSION_ALL - )); + ), null); $file = new OC_Connector_Sabre_File($view, $info); // action @@ -104,7 +104,7 @@ class Test_OC_Connector_Sabre_File extends \Test\TestCase { $info = new \OC\Files\FileInfo('/super*star.txt', null, null, array( 'permissions' => \OCP\Constants::PERMISSION_ALL - )); + ), null); $file = new OC_Connector_Sabre_File($view, $info); $file->setName('/super*star.txt'); } @@ -136,7 +136,7 @@ class Test_OC_Connector_Sabre_File extends \Test\TestCase { $info = new \OC\Files\FileInfo('/test.txt', null, null, array( 'permissions' => \OCP\Constants::PERMISSION_ALL - )); + ), null); $file = new OC_Connector_Sabre_File($view, $info); @@ -158,7 +158,7 @@ class Test_OC_Connector_Sabre_File extends \Test\TestCase { $info = new \OC\Files\FileInfo('/test.txt', null, null, array( 'permissions' => \OCP\Constants::PERMISSION_ALL - )); + ), null); $file = new OC_Connector_Sabre_File($view, $info); @@ -176,7 +176,7 @@ class Test_OC_Connector_Sabre_File extends \Test\TestCase { $info = new \OC\Files\FileInfo('/test.txt', null, null, array( 'permissions' => 0 - )); + ), null); $file = new OC_Connector_Sabre_File($view, $info); @@ -199,7 +199,7 @@ class Test_OC_Connector_Sabre_File extends \Test\TestCase { $info = new \OC\Files\FileInfo('/test.txt', null, null, array( 'permissions' => \OCP\Constants::PERMISSION_ALL - )); + ), null); $file = new OC_Connector_Sabre_File($view, $info); diff --git a/tests/lib/connector/sabre/objecttree.php b/tests/lib/connector/sabre/objecttree.php index d1de46d2ee7..2548066214b 100644 --- a/tests/lib/connector/sabre/objecttree.php +++ b/tests/lib/connector/sabre/objecttree.php @@ -101,7 +101,7 @@ class ObjectTree extends \Test\TestCase { private function moveTest($source, $dest, $updatables, $deletables) { $view = new TestDoubleFileView($updatables, $deletables); - $info = new FileInfo('', null, null, array()); + $info = new FileInfo('', null, null, array(), null); $rootDir = new OC_Connector_Sabre_Directory($view, $info); $objectTree = $this->getMock('\OC\Connector\Sabre\ObjectTree', diff --git a/tests/lib/files/node/file.php b/tests/lib/files/node/file.php index a1d2266edf7..e3b8019b4ca 100644 --- a/tests/lib/files/node/file.php +++ b/tests/lib/files/node/file.php @@ -22,7 +22,7 @@ class File extends \Test\TestCase { } protected function getFileInfo($data) { - return new FileInfo('', null, '', $data); + return new FileInfo('', null, '', $data, null); } public function testDelete() { diff --git a/tests/lib/files/node/folder.php b/tests/lib/files/node/folder.php index e69a2776979..bcd9cc93b5e 100644 --- a/tests/lib/files/node/folder.php +++ b/tests/lib/files/node/folder.php @@ -25,7 +25,7 @@ class Folder extends \Test\TestCase { } protected function getFileInfo($data) { - return new FileInfo('', null, '', $data); + return new FileInfo('', null, '', $data, null); } public function testDelete() { diff --git a/tests/lib/files/node/node.php b/tests/lib/files/node/node.php index 4697479ba95..49a2006c767 100644 --- a/tests/lib/files/node/node.php +++ b/tests/lib/files/node/node.php @@ -19,7 +19,7 @@ class Node extends \Test\TestCase { } protected function getFileInfo($data) { - return new FileInfo('', null, '', $data); + return new FileInfo('', null, '', $data, null); } public function testStat() { diff --git a/tests/lib/files/node/root.php b/tests/lib/files/node/root.php index 35bd462157e..a763428209c 100644 --- a/tests/lib/files/node/root.php +++ b/tests/lib/files/node/root.php @@ -21,7 +21,7 @@ class Root extends \Test\TestCase { } protected function getFileInfo($data) { - return new FileInfo('', null, '', $data); + return new FileInfo('', null, '', $data, null); } public function testGet() { diff --git a/tests/lib/memcache/redis.php b/tests/lib/memcache/redis.php new file mode 100644 index 00000000000..c0bd18b46f9 --- /dev/null +++ b/tests/lib/memcache/redis.php @@ -0,0 +1,29 @@ +<?php + +/** + * Copyright (c) 2013 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 Test\Memcache; + +class Redis extends Cache { + static public function setUpBeforeClass() { + parent::setUpBeforeClass(); + + if (!\OC\Memcache\Redis::isAvailable()) { + self::markTestSkipped('The redis extension is not available.'); + } + $instance = new \OC\Memcache\Redis(self::getUniqueID()); + if ($instance->set(self::getUniqueID(), self::getUniqueID()) === false) { + self::markTestSkipped('redis server seems to be down.'); + } + } + + protected function setUp() { + parent::setUp(); + $this->instance = new \OC\Memcache\Redis($this->getUniqueID()); + } +} diff --git a/tests/settings/controller/userscontrollertest.php b/tests/settings/controller/userscontrollertest.php index 0ac6d3f0c01..207943c4c87 100644 --- a/tests/settings/controller/userscontrollertest.php +++ b/tests/settings/controller/userscontrollertest.php @@ -45,6 +45,16 @@ class UsersControllerTest extends \Test\TestCase { ->will($this->returnCallback(function($text, $parameters = array()) { return vsprintf($text, $parameters); })); + $this->container['Defaults'] = $this->getMockBuilder('\OC_Defaults') + ->disableOriginalConstructor()->getMock(); + $this->container['Mail'] = $this->getMockBuilder('\OC_Mail') + ->disableOriginalConstructor()->getMock(); + $this->container['DefaultMailAddress'] = 'no-reply@owncloud.com'; + $this->container['Logger'] = $this->getMockBuilder('\OCP\ILogger') + ->disableOriginalConstructor()->getMock(); + $this->container['URLGenerator'] = $this->getMockBuilder('\OCP\IURLGenerator') + ->disableOriginalConstructor()->getMock(); + $this->usersController = $this->container['UsersController']; } @@ -473,4 +483,64 @@ class UsersControllerTest extends \Test\TestCase { $this->assertEquals($expectedResponse, $response); } + /** + * test if an invalid mail result in a failure response + */ + public function testCreateUnsuccessfulWithInvalidEMail() { + /** + * FIXME: Disabled due to missing DI on mail class. + * TODO: Re-enable when https://github.com/owncloud/core/pull/12085 is merged. + */ + $this->markTestSkipped('Disable test until OC_Mail is rewritten.'); + + $this->container['Mail'] + ->expects($this->once()) + ->method('validateAddress') + ->will($this->returnValue(false)); + + $expectedResponse = new DataResponse( + array( + 'message' => 'Invalid mail address' + ), + Http::STATUS_UNPROCESSABLE_ENTITY + ); + $response = $this->usersController->create('foo', 'password', array(), 'invalidMailAdress'); + $this->assertEquals($expectedResponse, $response); + } + + /** + * test if a valid mail result in a successful mail send + */ + public function testCreateSuccessfulWithValidEMail() { + /** + * FIXME: Disabled due to missing DI on mail class. + * TODO: Re-enable when https://github.com/owncloud/core/pull/12085 is merged. + */ + $this->markTestSkipped('Disable test until OC_Mail is rewritten.'); + + $this->container['Mail'] + ->expects($this->once()) + ->method('validateAddress') + ->will($this->returnValue(true)); + $this->container['Mail'] + ->expects($this->once()) + ->method('send') + ->with( + $this->equalTo('validMail@Adre.ss'), + $this->equalTo('foo'), + $this->anything(), + $this->anything(), + $this->anything(), + $this->equalTo('no-reply@owncloud.com'), + $this->equalTo(1), + $this->anything() + ); + $this->container['Logger'] + ->expects($this->never()) + ->method('error'); + + $response = $this->usersController->create('foo', 'password', array(), 'validMail@Adre.ss'); + $this->assertEquals(Http::STATUS_CREATED, $response->getStatus()); + } + } |