summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--apps/files/index.php2
-rwxr-xr-xapps/files_encryption/tests/share.php6
-rw-r--r--apps/files_external/templates/settings.php11
-rw-r--r--apps/files_sharing/lib/cache.php58
-rw-r--r--apps/files_sharing/tests/cache.php39
-rw-r--r--core/css/apps.css8
-rw-r--r--lib/private/connector/sabre/quotaplugin.php11
-rw-r--r--lib/private/filechunking.php40
-rw-r--r--lib/private/files/cache/cache.php18
-rw-r--r--lib/private/files/view.php19
-rw-r--r--lib/private/mail.php3
-rw-r--r--settings/css/settings.css27
-rw-r--r--settings/js/apps.js26
-rw-r--r--settings/templates/apps.php49
-rw-r--r--tests/lib/mail.php9
15 files changed, 241 insertions, 85 deletions
diff --git a/apps/files/index.php b/apps/files/index.php
index 73601d26217..4d765b69e41 100644
--- a/apps/files/index.php
+++ b/apps/files/index.php
@@ -40,7 +40,7 @@ $dir = isset($_GET['dir']) ? stripslashes($_GET['dir']) : '';
$dir = \OC\Files\Filesystem::normalizePath($dir);
$dirInfo = \OC\Files\Filesystem::getFileInfo($dir);
// Redirect if directory does not exist
-if (!$dirInfo->getType() === 'dir') {
+if (!$dirInfo || !$dirInfo->getType() === 'dir') {
header('Location: ' . OCP\Util::getScriptName() . '');
exit();
}
diff --git a/apps/files_encryption/tests/share.php b/apps/files_encryption/tests/share.php
index be56968ac09..1f57d7cb635 100755
--- a/apps/files_encryption/tests/share.php
+++ b/apps/files_encryption/tests/share.php
@@ -100,11 +100,11 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase {
$this->filename = 'share-tmp.test';
- // we don't want to tests with app files_trashbin enabled
- \OC_App::disable('files_trashbin');
-
// remember files_trashbin state
$this->stateFilesTrashbin = OC_App::isEnabled('files_trashbin');
+
+ // we don't want to tests with app files_trashbin enabled
+ \OC_App::disable('files_trashbin');
}
function tearDown() {
diff --git a/apps/files_external/templates/settings.php b/apps/files_external/templates/settings.php
index a2bdbcf4632..e8815acaf16 100644
--- a/apps/files_external/templates/settings.php
+++ b/apps/files_external/templates/settings.php
@@ -9,7 +9,7 @@
<th><?php p($l->t('External storage')); ?></th>
<th><?php p($l->t('Configuration')); ?></th>
<!--<th><?php p($l->t('Options')); ?></th> -->
- <?php if ($_['isAdminPage']) print_unescaped('<th>'.$l->t('Applicable').'</th>'); ?>
+ <?php if ($_['isAdminPage']) print_unescaped('<th>'.$l->t('Available for').'</th>'); ?>
<th>&nbsp;</th>
</tr>
</thead>
@@ -88,9 +88,12 @@
data-applicable-users='<?php if (isset($mount['applicable']['users']))
print_unescaped(json_encode($mount['applicable']['users'])); ?>'>
<select class="chzn-select"
- multiple style="width:20em;"
- data-placeholder="<?php p($l->t('None set')); ?>">
- <option value="all" <?php if (isset($mount['applicable']['users']) && in_array('all', $mount['applicable']['users'])) print_unescaped('selected="selected"');?> ><?php p($l->t('All Users')); ?></option>
+ multiple style="width:20em;"
+ data-placeholder="<?php p($l->t('No user or group')); ?>">
+ <option value="all"
+ <?php if (empty($mount['class']) || (isset($mount['applicable']['users']) && in_array('all', $mount['applicable']['users']))) print_unescaped('selected="selected"');?> >
+ <?php p($l->t('All Users')); ?>
+ </option>
<optgroup label="<?php p($l->t('Groups')); ?>">
<?php foreach ($_['groups'] as $group): ?>
<option value="<?php p($group); ?>(group)"
diff --git a/apps/files_sharing/lib/cache.php b/apps/files_sharing/lib/cache.php
index 01db29d72e2..eeb62c3cce2 100644
--- a/apps/files_sharing/lib/cache.php
+++ b/apps/files_sharing/lib/cache.php
@@ -20,6 +20,7 @@
*/
namespace OC\Files\Cache;
+
use OCP\Share_Backend_Collection;
/**
@@ -50,7 +51,7 @@ class Shared_Cache extends Cache {
\OC\Files\Filesystem::initMountPoints($source['fileOwner']);
$mount = \OC\Files\Filesystem::getMountByNumericId($source['storage']);
if (is_array($mount)) {
- $fullPath = $mount[key($mount)]->getMountPoint().$source['path'];
+ $fullPath = $mount[key($mount)]->getMountPoint() . $source['path'];
list($storage, $internalPath) = \OC\Files\Filesystem::resolvePath($fullPath);
if ($storage) {
$this->files[$target] = $internalPath;
@@ -75,7 +76,7 @@ class Shared_Cache extends Cache {
/**
* get the stored metadata of a file or folder
*
- * @param string/int $file
+ * @param string /int $file
* @return array
*/
public function get($file) {
@@ -95,8 +96,8 @@ class Shared_Cache extends Cache {
} else {
$query = \OC_DB::prepare(
'SELECT `fileid`, `storage`, `path`, `parent`, `name`, `mimetype`, `mimepart`,'
- .' `size`, `mtime`, `encrypted`, `unencrypted_size`'
- .' FROM `*PREFIX*filecache` WHERE `fileid` = ?');
+ . ' `size`, `mtime`, `encrypted`, `unencrypted_size`'
+ . ' FROM `*PREFIX*filecache` WHERE `fileid` = ?');
$result = $query->execute(array($file));
$data = $result->fetchRow();
$data['fileid'] = (int)$data['fileid'];
@@ -288,8 +289,7 @@ class Shared_Cache extends Cache {
foreach ($files as $file) {
if ($file['mimetype'] === 'httpd/unix-directory') {
$exploreDirs[] = ltrim($dir . '/' . $file['name'], '/');
- }
- else if (($mimepart && $file['mimepart'] === $mimepart) || ($mimetype && $file['mimetype'] === $mimetype)) {
+ } else if (($mimepart && $file['mimepart'] === $mimepart) || ($mimetype && $file['mimetype'] === $mimetype)) {
// usersPath not reliable
//$file['path'] = $file['usersPath'];
$file['path'] = ltrim($dir . '/' . $file['name'], '/');
@@ -344,8 +344,6 @@ class Shared_Cache extends Cache {
if ($row['encrypted'] or ($row['unencrypted_size'] > 0 and $row['mimetype'] === 'httpd/unix-directory')) {
$row['encrypted_size'] = $row['size'];
$row['size'] = $row['unencrypted_size'];
- } else {
- $row['size'] = $row['size'];
}
$files[] = $row;
}
@@ -402,4 +400,48 @@ class Shared_Cache extends Cache {
return false;
}
+ /**
+ * get the path of a file on this storage by it's id
+ *
+ * @param int $id
+ * @param string $pathEnd (optional) used internally for recursive calls
+ * @return string | null
+ */
+ public function getPathById($id, $pathEnd = '') {
+ // direct shares are easy
+ if ($path = $this->getShareById($id)) {
+ return $path . $pathEnd;
+ } else {
+ // if the item is a direct share we try and get the path of the parent and append the name of the item to it
+ list($parent, $name) = $this->getParentInfo($id);
+ if ($parent > 0) {
+ return $this->getPathById($parent, '/' . $name . $pathEnd);
+ } else {
+ return null;
+ }
+ }
+ }
+
+ private function getShareById($id) {
+ $item = \OCP\Share::getItemSharedWithBySource('file', $id);
+ if ($item) {
+ return trim($item['file_target'], '/');
+ }
+ $item = \OCP\Share::getItemSharedWithBySource('folder', $id);
+ if ($item) {
+ return trim($item['file_target'], '/');
+ }
+ return null;
+ }
+
+ private function getParentInfo($id) {
+ $sql = 'SELECT `parent`, `name` FROM `*PREFIX*filecache` WHERE `fileid` = ?';
+ $query = \OC_DB::prepare($sql);
+ $result = $query->execute(array($id));
+ if ($row = $result->fetchRow()) {
+ return array($row['parent'], $row['name']);
+ } else {
+ return array(-1, '');
+ }
+ }
}
diff --git a/apps/files_sharing/tests/cache.php b/apps/files_sharing/tests/cache.php
index a75e1860527..47969833ab5 100644
--- a/apps/files_sharing/tests/cache.php
+++ b/apps/files_sharing/tests/cache.php
@@ -246,4 +246,43 @@ class Test_Files_Sharing_Cache extends Test_Files_Sharing_Base {
}
}
+ public function testGetPathByIdDirectShare() {
+ self::loginHelper(self::TEST_FILES_SHARING_API_USER1);
+ \OC\Files\Filesystem::file_put_contents('test.txt', 'foo');
+ $info = \OC\Files\Filesystem::getFileInfo('test.txt');
+ \OCP\Share::shareItem('file', $info->getId(), \OCP\Share::SHARE_TYPE_USER, self::TEST_FILES_SHARING_API_USER2, \OCP\PERMISSION_ALL);
+ \OC_Util::tearDownFS();
+
+ self::loginHelper(self::TEST_FILES_SHARING_API_USER2);
+ $this->assertTrue(\OC\Files\Filesystem::file_exists('/Shared/test.txt'));
+ list($sharedStorage) = \OC\Files\Filesystem::resolvePath('/' . self::TEST_FILES_SHARING_API_USER2 . '/files/Shared/test.txt');
+ /**
+ * @var \OC\Files\Storage\Shared $sharedStorage
+ */
+
+ $sharedCache = $sharedStorage->getCache();
+ $this->assertEquals('test.txt', $sharedCache->getPathById($info->getId()));
+ }
+
+ public function testGetPathByIdShareSubFolder() {
+ self::loginHelper(self::TEST_FILES_SHARING_API_USER1);
+ \OC\Files\Filesystem::mkdir('foo');
+ \OC\Files\Filesystem::mkdir('foo/bar');
+ \OC\Files\Filesystem::touch('foo/bar/test.txt', 'bar');
+ $folderInfo = \OC\Files\Filesystem::getFileInfo('foo');
+ $fileInfo = \OC\Files\Filesystem::getFileInfo('foo/bar/test.txt');
+ \OCP\Share::shareItem('folder', $folderInfo->getId(), \OCP\Share::SHARE_TYPE_USER, self::TEST_FILES_SHARING_API_USER2, \OCP\PERMISSION_ALL);
+ \OC_Util::tearDownFS();
+
+ self::loginHelper(self::TEST_FILES_SHARING_API_USER2);
+ $this->assertTrue(\OC\Files\Filesystem::file_exists('/Shared/foo'));
+ list($sharedStorage) = \OC\Files\Filesystem::resolvePath('/' . self::TEST_FILES_SHARING_API_USER2 . '/files/Shared/foo');
+ /**
+ * @var \OC\Files\Storage\Shared $sharedStorage
+ */
+
+ $sharedCache = $sharedStorage->getCache();
+ $this->assertEquals('foo', $sharedCache->getPathById($folderInfo->getId()));
+ $this->assertEquals('foo/bar/test.txt', $sharedCache->getPathById($fileInfo->getId()));
+ }
}
diff --git a/core/css/apps.css b/core/css/apps.css
index 8eb3bdd683e..ebf277faf46 100644
--- a/core/css/apps.css
+++ b/core/css/apps.css
@@ -29,10 +29,14 @@
-moz-box-sizing: border-box; box-sizing: border-box;
}
#app-navigation .active,
-#app-navigation .active a,
-#app-navigation li:hover > a {
+#app-navigation .active a {
background-color: #ddd;
}
+#app-navigation li:hover > a,
+#app-navigation .selected,
+#app-navigation .selected a {
+ background-color: #ccc;
+}
/* special rules for first-level entries and folders */
#app-navigation > ul > li {
diff --git a/lib/private/connector/sabre/quotaplugin.php b/lib/private/connector/sabre/quotaplugin.php
index 8099794f670..227e684741c 100644
--- a/lib/private/connector/sabre/quotaplugin.php
+++ b/lib/private/connector/sabre/quotaplugin.php
@@ -56,8 +56,19 @@ class OC_Connector_Sabre_QuotaPlugin extends Sabre_DAV_ServerPlugin {
$uri='/'.$uri;
}
list($parentUri, $newName) = Sabre_DAV_URLUtil::splitPath($uri);
+ $req = $this->server->httpRequest;
+ if ($req->getHeader('OC-Chunked')) {
+ $info = OC_FileChunking::decodeName($newName);
+ $chunkHandler = new OC_FileChunking($info);
+ // substract the already uploaded size to see whether
+ // there is still enough space for the remaining chunks
+ $length -= $chunkHandler->getCurrentSize();
+ }
$freeSpace = $this->getFreeSpace($parentUri);
if ($freeSpace !== \OC\Files\SPACE_UNKNOWN && $length > $freeSpace) {
+ if (isset($chunkHandler)) {
+ $chunkHandler->cleanup();
+ }
throw new Sabre_DAV_Exception_InsufficientStorage();
}
}
diff --git a/lib/private/filechunking.php b/lib/private/filechunking.php
index be7f4e14a11..1da02fc81e3 100644
--- a/lib/private/filechunking.php
+++ b/lib/private/filechunking.php
@@ -64,20 +64,46 @@ class OC_FileChunking {
return $parts == $this->info['chunkcount'];
}
+ /**
+ * Assembles the chunks into the file specified by the path.
+ * Chunks are deleted afterwards.
+ *
+ * @param string $f target path
+ *
+ * @return assembled file size
+ *
+ * @throws \OC\InsufficientStorageException when file could not be fully
+ * assembled due to lack of free space
+ */
public function assemble($f) {
$cache = $this->getCache();
$prefix = $this->getPrefix();
$count = 0;
- for($i=0; $i < $this->info['chunkcount']; $i++) {
+ for ($i = 0; $i < $this->info['chunkcount']; $i++) {
$chunk = $cache->get($prefix.$i);
+ // remove after reading to directly save space
+ $cache->remove($prefix.$i);
$count += fwrite($f, $chunk);
}
- $this->cleanup();
return $count;
}
/**
+ * Returns the size of the chunks already present
+ * @return size in bytes
+ */
+ public function getCurrentSize() {
+ $cache = $this->getCache();
+ $prefix = $this->getPrefix();
+ $total = 0;
+ for ($i = 0; $i < $this->info['chunkcount']; $i++) {
+ $total += $cache->size($prefix.$i);
+ }
+ return $total;
+ }
+
+ /**
* Removes all chunks which belong to this transmission
*/
public function cleanup() {
@@ -128,7 +154,15 @@ class OC_FileChunking {
}
/**
- * @param string $path
+ * Assembles the chunks into the file specified by the path.
+ * Also triggers the relevant hooks and proxies.
+ *
+ * @param string $path target path
+ *
+ * @return assembled file size or false if file could not be created
+ *
+ * @throws \OC\InsufficientStorageException when file could not be fully
+ * assembled due to lack of free space
*/
public function file_assemble($path) {
$absolutePath = \OC\Files\Filesystem::normalizePath(\OC\Files\Filesystem::getView()->getAbsolutePath($path));
diff --git a/lib/private/files/cache/cache.php b/lib/private/files/cache/cache.php
index abc11e76470..1c9de56f8c5 100644
--- a/lib/private/files/cache/cache.php
+++ b/lib/private/files/cache/cache.php
@@ -594,7 +594,25 @@ class Cache {
}
/**
+ * get the path of a file on this storage by it's id
+ *
+ * @param int $id
+ * @return string | null
+ */
+ public function getPathById($id) {
+ $sql = 'SELECT `path` FROM `*PREFIX*filecache` WHERE `fileid` = ? AND `storage` = ?';
+ $result = \OC_DB::executeAudited($sql, array($id, $this->getNumericStorageId()));
+ if ($row = $result->fetchRow()) {
+ return $row['path'];
+ } else {
+ return null;
+ }
+ }
+
+ /**
* get the storage id of the storage for a file and the internal path of the file
+ * unlike getPathById this does not limit the search to files on this storage and
+ * instead does a global search in the cache table
*
* @param int $id
* @return array, first element holding the storage id, second the path
diff --git a/lib/private/files/view.php b/lib/private/files/view.php
index f06c2fcd66c..90b0da09c37 100644
--- a/lib/private/files/view.php
+++ b/lib/private/files/view.php
@@ -1129,15 +1129,22 @@ class View {
* @return string
*/
public function getPath($id) {
- list($storage, $internalPath) = Cache\Cache::getById($id);
- $mounts = Filesystem::getMountByStorageId($storage);
+ $manager = Filesystem::getMountManager();
+ $mounts = $manager->findIn($this->fakeRoot);
+ $mounts[] = $manager->find($this->fakeRoot);
+ // reverse the array so we start with the storage this view is in
+ // which is the most likely to contain the file we're looking for
+ $mounts = array_reverse($mounts);
foreach ($mounts as $mount) {
/**
- * @var \OC\Files\Mount $mount
+ * @var \OC\Files\Mount\Mount $mount
*/
- $fullPath = $mount->getMountPoint() . $internalPath;
- if (!is_null($path = $this->getRelativePath($fullPath))) {
- return $path;
+ $cache = $mount->getStorage()->getCache();
+ if ($internalPath = $cache->getPathById($id)) {
+ $fullPath = $mount->getMountPoint() . $internalPath;
+ if (!is_null($path = $this->getRelativePath($fullPath))) {
+ return $path;
+ }
}
}
return null;
diff --git a/lib/private/mail.php b/lib/private/mail.php
index 79f51609631..f9083cc4e64 100644
--- a/lib/private/mail.php
+++ b/lib/private/mail.php
@@ -137,6 +137,9 @@ class OC_Mail {
* @return string
*/
public static function buildAsciiEmail($emailAddress) {
+ if (!function_exists('idn_to_ascii')) {
+ return $emailAddress;
+ }
list($name, $domain) = explode('@', $emailAddress, 2);
$domain = idn_to_ascii($domain);
diff --git a/settings/css/settings.css b/settings/css/settings.css
index 5dd41256918..b2c09571404 100644
--- a/settings/css/settings.css
+++ b/settings/css/settings.css
@@ -57,13 +57,7 @@ tr:hover>td.password>span, tr:hover>td.displayName>span { margin:0; cursor:point
tr:hover>td.remove>a, tr:hover>td.password>img,tr:hover>td.displayName>img, tr:hover>td.quota>img { visibility:visible; cursor:pointer; }
tr:hover>td.remove>a { float:right; }
-li.selected,
-#leftcontent li.selected {
- background-color: #ddd;
-}
-
table.grid { width:100%; }
-#rightcontent { padding-left: 10px; }
div.quota {
float: right;
display: block;
@@ -101,30 +95,21 @@ select.quota.active { background: #fff; }
/* APPS */
.appinfo { margin: 1em 40px; }
h3 { font-size: 1.4em; font-weight: bold; }
-ul.applist a {
- height: 2.2em;
- padding: 0.2em 0.2em 0.2em 0.8em !important;
+#app-navigation {
+ padding-bottom: 0px;
}
-ul.applist .app-external {
- width: 100%;
-}
-li { color:#888; }
-li.active { color:#000; }
-#leftcontent .appwarning {
+#app-navigation .appwarning {
background: #fcc;
}
-#leftcontent .appwarning:hover {
+#app-navigation.appwarning:hover {
background: #fbb;
}
small.externalapp { color:#FFF; background-color:#BBB; font-weight:bold; font-size: 0.6em; margin: 0; padding: 0.1em 0.2em; border-radius: 4px;}
-small.externalapp.list { float: right; }
small.recommendedapp { color:#FFF; background-color:#888; font-weight:bold; font-size: 0.6em; margin: 0; padding: 0.1em 0.2em; border-radius: 4px;}
-small.recommendedapp.list { float: right; }
+small.externalapp.list, small.recommendedapp.list { position: absolute; right: 10px; top: 12px; }
span.version { margin-left:1em; margin-right:1em; color:#555; }
-.app { position: relative; display: inline-block; padding: 0.2em 0 0.2em 0 !important; text-overflow: hidden; overflow: hidden; white-space: nowrap; /*transition: .2s max-width linear; -o-transition: .2s max-width linear; -moz-transition: .2s max-width linear; -webkit-transition: .2s max-width linear; -ms-transition: .2s max-width linear;*/ }
-.app.externalapp { max-width: 12.5em; }
-.app.recommendedapp { max-width: 12.5em; }
+
/* Transition to complete width! */
.app:hover, .app:active { max-width: inherit; }
diff --git a/settings/js/apps.js b/settings/js/apps.js
index 3dbc8a2f7c2..05db4c9a048 100644
--- a/settings/js/apps.js
+++ b/settings/js/apps.js
@@ -8,7 +8,7 @@
OC.Settings = OC.Settings || {};
OC.Settings.Apps = OC.Settings.Apps || {
loadApp:function(app) {
- var page = $('#rightcontent');
+ var page = $('#app-content');
page.find('p.license').show();
page.find('span.name').text(app.name);
page.find('small.externalapp').text(app.internallabel);
@@ -82,16 +82,16 @@ OC.Settings.Apps = OC.Settings.Apps || {
page.find('p.appslink').hide();
page.find('span.score').hide();
}
- if (typeof($('#leftcontent li[data-id="'+app.id+'"]').data('errormsg')) !== "undefined") {
+ if (typeof($('#app-navigation ul li[data-id="'+app.id+'"]').data('errormsg')) !== "undefined") {
page.find(".warning").show();
- page.find(".warning").text($('#leftcontent li[data-id="'+app.id+'"]').data('errormsg'));
+ page.find(".warning").text($('#app-navigation ul li[data-id="'+app.id+'"]').data('errormsg'));
} else {
page.find(".warning").hide();
}
},
enableApp:function(appid, active, element) {
console.log('enableApp:', appid, active, element);
- var appitem=$('#leftcontent li[data-id="'+appid+'"]');
+ var appitem=$('#app-navigation ul li[data-id="'+appid+'"]');
element.val(t('settings','Please wait....'));
if(active) {
$.post(OC.filePath('settings','ajax','disableapp.php'),{appid:appid},function(result) {
@@ -160,7 +160,7 @@ OC.Settings.Apps = OC.Settings.Apps || {
},
insertApp:function(appdata) {
- var applist = $('#leftcontent li');
+ var applist = $('#app-navigation ul li');
var app =
$('<li data-id="' + appdata.id + '" data-type="external" data-installed="0">'
+ '<a class="app externalapp" href="' + OC.filePath('settings', 'apps', 'index.php') + '&appid=' + appdata.id+'">'
@@ -242,30 +242,30 @@ OC.Settings.Apps = OC.Settings.Apps || {
};
$(document).ready(function(){
- $('#leftcontent li').each(function(index,li){
+ $('#app-navigation ul li').each(function(index,li){
var app = OC.get('appData_'+$(li).data('id'));
$(li).data('app',app);
$(this).find('span.hidden').remove();
});
- $('#leftcontent li').keydown(function(event) {
+ $('#app-navigation ul li').keydown(function(event) {
if (event.which === 13 || event.which === 32) {
$(event.target).click();
}
return false;
});
- $(document).on('click', '#leftcontent', function(event){
+ $(document).on('click', '#app-navigation', function(event){
var tgt = $(event.target);
if (tgt.is('li') || tgt.is('a')) {
var item = tgt.is('li') ? $(tgt) : $(tgt).parent();
var app = item.data('app');
OC.Settings.Apps.loadApp(app);
- $('#leftcontent .selected').removeClass('selected');
+ $('#app-navigation .selected').removeClass('selected');
item.addClass('selected');
}
return false;
});
- $('#rightcontent input.enable').click(function(){
+ $('#app-content input.enable').click(function(){
var element = $(this);
var appid=$(this).data('appid');
var active=$(this).data('active');
@@ -273,7 +273,7 @@ $(document).ready(function(){
OC.Settings.Apps.enableApp(appid, active, element);
}
});
- $('#rightcontent input.update').click(function(){
+ $('#app-content input.update').click(function(){
var element = $(this);
var appid=$(this).data('appid');
if(appid) {
@@ -282,11 +282,11 @@ $(document).ready(function(){
});
if(appid) {
- var item = $('#leftcontent li[data-id="'+appid+'"]');
+ var item = $('#app-navigation ul li[data-id="'+appid+'"]');
if(item) {
item.trigger('click');
item.addClass('active');
- $('#leftcontent').animate({scrollTop: $(item).offset().top-70}, 'slow','swing');
+ $('#app-navigation').animate({scrollTop: $(item).offset().top-70}, 'slow','swing');
}
}
});
diff --git a/settings/templates/apps.php b/settings/templates/apps.php
index 4c77c62f511..b7f3b6121ad 100644
--- a/settings/templates/apps.php
+++ b/settings/templates/apps.php
@@ -7,32 +7,33 @@
src="<?php print_unescaped(OC_Helper::linkToRoute('apps_custom'));?>?appid=<?php p($_['appid']); ?>"></script>
<script type="text/javascript" src="<?php print_unescaped(OC_Helper::linkTo('settings/js', 'apps.js'));?>"></script>
+<div id="app-navigation">
+ <ul class="applist">
+ <?php if(OC_Config::getValue('appstoreenabled', true) === true): ?>
+ <li>
+ <a class="app-external" target="_blank" href="http://owncloud.org/dev"><?php p($l->t('Add your App'));?> …</a>
+ </li>
+ <?php endif; ?>
-<ul id="leftcontent" class="applist">
- <?php if(OC_Config::getValue('appstoreenabled', true) === true): ?>
- <li>
- <a class="app-external" target="_blank" href="http://owncloud.org/dev"><?php p($l->t('Add your App'));?> …</a>
- </li>
- <?php endif; ?>
+ <?php foreach($_['apps'] as $app):?>
+ <li <?php if($app['active']) print_unescaped('class="active"')?> data-id="<?php p($app['id']) ?>"
+ <?php if ( isset( $app['ocs_id'] ) ) { print_unescaped("data-id-ocs=\"{".OC_Util::sanitizeHTML($app['ocs_id'])."}\""); } ?>
+ data-type="<?php p($app['internal'] ? 'internal' : 'external') ?>" data-installed="1">
+ <a class="app<?php if(!$app['internal']) p(' externalapp') ?>"
+ href="?appid=<?php p($app['id']) ?>"><?php p($app['name']) ?></a>
+ <?php if(!$app['internal'])
+ print_unescaped('<small class="'.OC_Util::sanitizeHTML($app['internalclass']).' list">'.OC_Util::sanitizeHTML($app['internallabel']).'</small>') ?>
+ </li>
+ <?php endforeach;?>
- <?php foreach($_['apps'] as $app):?>
- <li <?php if($app['active']) print_unescaped('class="active"')?> data-id="<?php p($app['id']) ?>"
- <?php if ( isset( $app['ocs_id'] ) ) { print_unescaped("data-id-ocs=\"{".OC_Util::sanitizeHTML($app['ocs_id'])."}\""); } ?>
- data-type="<?php p($app['internal'] ? 'internal' : 'external') ?>" data-installed="1">
- <a class="app<?php if(!$app['internal']) p(' externalapp') ?>"
- href="?appid=<?php p($app['id']) ?>"><?php p($app['name']) ?></a>
- <?php if(!$app['internal'])
- print_unescaped('<small class="'.OC_Util::sanitizeHTML($app['internalclass']).' list">'.OC_Util::sanitizeHTML($app['internallabel']).'</small>') ?>
- </li>
- <?php endforeach;?>
-
- <?php if(OC_Config::getValue('appstoreenabled', true) === true): ?>
- <li>
- <a class="app-external" target="_blank" href="http://apps.owncloud.com"><?php p($l->t('More Apps'));?> …</a>
- </li>
- <?php endif; ?>
-</ul>
-<div id="rightcontent">
+ <?php if(OC_Config::getValue('appstoreenabled', true) === true): ?>
+ <li>
+ <a class="app-external" target="_blank" href="http://apps.owncloud.com"><?php p($l->t('More Apps'));?> …</a>
+ </li>
+ <?php endif; ?>
+ </ul>
+</div>
+<div id="app-content">
<div class="appinfo">
<h3><strong><span class="name"><?php p($l->t('Select an App'));?></span></strong><span
class="version"></span><small class="externalapp" style="visibility:hidden;"></small></h3>
diff --git a/tests/lib/mail.php b/tests/lib/mail.php
index a88a9d797ae..3cc9868e25e 100644
--- a/tests/lib/mail.php
+++ b/tests/lib/mail.php
@@ -8,6 +8,15 @@
class Test_Mail extends PHPUnit_Framework_TestCase {
+ protected function setUp()
+ {
+ if (!function_exists('idn_to_ascii')) {
+ $this->markTestSkipped(
+ 'The intl extension is not available.'
+ );
+ }
+ }
+
/**
* @dataProvider buildAsciiEmailProvider
* @param $expected