Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nextcloud/server.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFrank Karlitschek <frank@owncloud.org>2014-07-31 01:40:05 +0400
committerFrank Karlitschek <frank@owncloud.org>2014-07-31 01:40:05 +0400
commitc0f0e79b5e62e229cc3e3a0fa597239b5eebccaf (patch)
tree702174b82cfd2adc4d38f032003810a4f5447c8e
parent727374a6f3e693b3237d6766d3bce86d73c00833 (diff)
parenta0f024fec22854509de19a1aa735a1567c3b534c (diff)
Merge branch 'stable7' of https://github.com/owncloud/core into stable7v7.0.1RC1
m---------3rdparty0
-rw-r--r--apps/files/css/files.css14
-rw-r--r--apps/files/js/filelist.js28
-rw-r--r--apps/files/tests/js/filelistSpec.js51
-rw-r--r--apps/files_encryption/hooks/hooks.php54
-rwxr-xr-xapps/files_encryption/lib/helper.php4
-rw-r--r--apps/files_encryption/settings-admin.php3
-rw-r--r--apps/files_encryption/templates/settings-admin.php4
-rw-r--r--apps/files_encryption/templates/settings-personal.php9
-rw-r--r--apps/files_encryption/tests/hooks.php52
-rw-r--r--apps/files_sharing/ajax/publicpreview.php4
-rw-r--r--apps/files_sharing/appinfo/update.php6
-rw-r--r--apps/files_sharing/js/sharedfilelist.js4
-rw-r--r--apps/files_sharing/lib/api.php29
-rw-r--r--apps/files_sharing/lib/external/storage.php9
-rw-r--r--apps/files_sharing/templates/public.php2
-rw-r--r--apps/files_sharing/tests/api.php74
-rw-r--r--apps/files_sharing/tests/update.php1
-rw-r--r--apps/files_versions/appinfo/app.php7
-rw-r--r--apps/files_versions/lib/hooks.php30
-rw-r--r--apps/files_versions/lib/versions.php70
-rw-r--r--apps/files_versions/tests/versions.php108
-rw-r--r--core/ajax/preview.php4
-rw-r--r--core/ajax/share.php16
-rw-r--r--core/css/header.css2
-rw-r--r--core/css/icons.css3
-rw-r--r--core/css/mobile.css16
-rw-r--r--core/css/styles.css29
-rw-r--r--core/img/actions/public.pngbin338 -> 307 bytes
-rw-r--r--core/img/actions/public.svg7
-rw-r--r--core/img/actions/search-white.pngbin0 -> 309 bytes
-rw-r--r--core/img/actions/search-white.svg5
-rw-r--r--core/img/filetypes/folder-public.pngbin1308 -> 1251 bytes
-rw-r--r--core/img/filetypes/folder-public.svg41
-rw-r--r--core/js/js.js16
-rw-r--r--core/js/share.js28
-rw-r--r--core/js/tests/specs/coreSpec.js6
-rw-r--r--core/js/tests/specs/shareSpec.js139
-rw-r--r--core/lostpassword/controller/lostcontroller.php25
-rw-r--r--cron.php5
-rw-r--r--lib/base.php9
-rw-r--r--lib/private/backgroundjob/joblist.php5
-rw-r--r--lib/private/contacts/localaddressbook.php104
-rw-r--r--lib/private/db/mdb2schemamanager.php3
-rw-r--r--lib/private/db/migrator.php4
-rw-r--r--lib/private/db/mysqlmigrator.php4
-rw-r--r--lib/private/db/sqlitemigrator.php39
-rw-r--r--lib/private/image.php8
-rwxr-xr-xlib/private/preview.php10
-rw-r--r--lib/private/preview/mp3.php2
-rw-r--r--lib/private/server.php6
-rw-r--r--lib/private/share/share.php64
-rw-r--r--lib/private/updater.php5
-rw-r--r--lib/private/user/user.php2
-rwxr-xr-xlib/private/util.php24
-rw-r--r--lib/public/appframework/http/templateresponse.php4
-rw-r--r--lib/public/iuser.php6
-rw-r--r--lib/public/share.php5
-rw-r--r--lib/public/util.php9
-rwxr-xr-xsettings/admin.php8
-rw-r--r--settings/js/apps.js2
-rw-r--r--tests/lib/contacts/localadressbook.php95
-rw-r--r--tests/lib/db/mysqlmigration.php39
-rw-r--r--tests/lib/db/sqlitemigration.php39
-rw-r--r--tests/lib/share/share.php107
65 files changed, 1308 insertions, 200 deletions
diff --git a/3rdparty b/3rdparty
-Subproject 6ece897f4435c246730db947576ad6f8a94dbdb
+Subproject b958a1e609b6bd09dd0fa29943b48eb024a31b7
diff --git a/apps/files/css/files.css b/apps/files/css/files.css
index 287dedc23f2..4a8bd5bb30f 100644
--- a/apps/files/css/files.css
+++ b/apps/files/css/files.css
@@ -152,16 +152,20 @@ table th .columntitle.name {
padding-right: 80px;
margin-left: 50px;
}
-/* hover effect on sortable column */
-table th a.columntitle:hover {
- color: #000;
-}
+
+.sort-indicator.hidden { visibility: hidden; }
table th .sort-indicator {
width: 10px;
height: 8px;
margin-left: 10px;
display: inline-block;
}
+table th:hover .sort-indicator.hidden {
+ width: 10px;
+ height: 8px;
+ margin-left: 10px;
+ visibility: visible;
+}
table th, table td { border-bottom:1px solid #ddd; text-align:left; font-weight:normal; }
table td {
padding: 0 15px;
@@ -367,7 +371,6 @@ table td.filename .uploadtext {
left: 18px;
}
-
#fileList tr td.filename {
position: relative;
width: 100%;
@@ -432,7 +435,6 @@ a.action>img {
margin-bottom: -1px;
}
-
#fileList a.action {
display: inline;
padding: 18px 8px;
diff --git a/apps/files/js/filelist.js b/apps/files/js/filelist.js
index 61e73b7bebc..4fa8ca65e39 100644
--- a/apps/files/js/filelist.js
+++ b/apps/files/js/filelist.js
@@ -18,8 +18,8 @@
this.initialize($el, options);
};
FileList.prototype = {
- SORT_INDICATOR_ASC_CLASS: 'icon-triangle-s',
- SORT_INDICATOR_DESC_CLASS: 'icon-triangle-n',
+ SORT_INDICATOR_ASC_CLASS: 'icon-triangle-n',
+ SORT_INDICATOR_DESC_CLASS: 'icon-triangle-s',
id: 'files',
appName: t('files', 'Files'),
@@ -371,7 +371,12 @@
this.setSort(sort, (this._sortDirection === 'desc')?'asc':'desc');
}
else {
- this.setSort(sort, 'asc');
+ if ( sort === 'name' ) { //default sorting of name is opposite to size and mtime
+ this.setSort(sort, 'asc');
+ }
+ else {
+ this.setSort(sort, 'desc');
+ }
}
this.reload();
}
@@ -707,6 +712,7 @@
* @param options map of attributes:
* - "updateSummary": true to update the summary after adding (default), false otherwise
* - "silent": true to prevent firing events like "fileActionsReady"
+ * - "animate": true to animate preview loading (defaults to true here)
* @return new tr element (not appended to the table)
*/
add: function(fileData, options) {
@@ -714,7 +720,7 @@
var $tr;
var $rows;
var $insertionPoint;
- options = options || {};
+ options = _.extend({animate: true}, options || {});
// there are three situations to cover:
// 1) insertion point is visible on the current page
@@ -772,6 +778,7 @@
* @param options map of attributes:
* - "index" optional index at which to insert the element
* - "updateSummary" true to update the summary after adding (default), false otherwise
+ * - "animate" true to animate the preview rendering
* @return new tr element (not appended to the table)
*/
_renderRow: function(fileData, options) {
@@ -813,7 +820,7 @@
if (fileData.isPreviewAvailable) {
// lazy load / newly inserted td ?
- if (!fileData.icon) {
+ if (options.animate) {
this.lazyLoadPreview({
path: path + '/' + fileData.name,
mime: mime,
@@ -914,16 +921,25 @@
this._sort = sort;
this._sortDirection = (direction === 'desc')?'desc':'asc';
this._sortComparator = comparator;
+
if (direction === 'desc') {
this._sortComparator = function(fileInfo1, fileInfo2) {
return -comparator(fileInfo1, fileInfo2);
};
}
this.$el.find('thead th .sort-indicator')
- .removeClass(this.SORT_INDICATOR_ASC_CLASS + ' ' + this.SORT_INDICATOR_DESC_CLASS);
+ .removeClass(this.SORT_INDICATOR_ASC_CLASS)
+ .removeClass(this.SORT_INDICATOR_DESC_CLASS)
+ .toggleClass('hidden', true)
+ .addClass(this.SORT_INDICATOR_DESC_CLASS);
+
this.$el.find('thead th.column-' + sort + ' .sort-indicator')
+ .removeClass(this.SORT_INDICATOR_ASC_CLASS)
+ .removeClass(this.SORT_INDICATOR_DESC_CLASS)
+ .toggleClass('hidden', false)
.addClass(direction === 'desc' ? this.SORT_INDICATOR_DESC_CLASS : this.SORT_INDICATOR_ASC_CLASS);
},
+
/**
* Reloads the file list using ajax call
*
diff --git a/apps/files/tests/js/filelistSpec.js b/apps/files/tests/js/filelistSpec.js
index ae22ae0123e..0580177c5ff 100644
--- a/apps/files/tests/js/filelistSpec.js
+++ b/apps/files/tests/js/filelistSpec.js
@@ -1696,7 +1696,7 @@ describe('OCA.Files.FileList tests', function() {
var url = fakeServer.requests[0].url;
var query = OC.parseQueryString(url.substr(url.indexOf('?') + 1));
expect(query.sort).toEqual('size');
- expect(query.sortdirection).toEqual('asc');
+ expect(query.sortdirection).toEqual('desc');
});
it('Toggles sort direction when clicking on already sorted column', function() {
fileList.$el.find('.column-name .columntitle').click();
@@ -1710,37 +1710,51 @@ describe('OCA.Files.FileList tests', function() {
var ASC_CLASS = fileList.SORT_INDICATOR_ASC_CLASS;
var DESC_CLASS = fileList.SORT_INDICATOR_DESC_CLASS;
fileList.$el.find('.column-size .columntitle').click();
- // moves triangle to size column
+ // moves triangle to size column, check indicator on name is hidden
expect(
- fileList.$el.find('.column-name .sort-indicator').hasClass(ASC_CLASS + ' ' + DESC_CLASS)
+ fileList.$el.find('.column-name .sort-indicator').hasClass('hidden')
+ ).toEqual(true);
+ // check indicator on size is visible and defaults to descending
+ expect(
+ fileList.$el.find('.column-size .sort-indicator').hasClass('hidden')
).toEqual(false);
expect(
- fileList.$el.find('.column-size .sort-indicator').hasClass(ASC_CLASS)
+ fileList.$el.find('.column-size .sort-indicator').hasClass(DESC_CLASS)
).toEqual(true);
// click again on size column, reverses direction
fileList.$el.find('.column-size .columntitle').click();
expect(
- fileList.$el.find('.column-size .sort-indicator').hasClass(DESC_CLASS)
+ fileList.$el.find('.column-size .sort-indicator').hasClass('hidden')
+ ).toEqual(false);
+ expect(
+ fileList.$el.find('.column-size .sort-indicator').hasClass(ASC_CLASS)
).toEqual(true);
// click again on size column, reverses direction
fileList.$el.find('.column-size .columntitle').click();
expect(
- fileList.$el.find('.column-size .sort-indicator').hasClass(ASC_CLASS)
+ fileList.$el.find('.column-size .sort-indicator').hasClass('hidden')
+ ).toEqual(false);
+ expect(
+ fileList.$el.find('.column-size .sort-indicator').hasClass(DESC_CLASS)
).toEqual(true);
// click on mtime column, moves indicator there
fileList.$el.find('.column-mtime .columntitle').click();
expect(
- fileList.$el.find('.column-size .sort-indicator').hasClass(ASC_CLASS + ' ' + DESC_CLASS)
+ fileList.$el.find('.column-size .sort-indicator').hasClass('hidden')
+ ).toEqual(true);
+ expect(
+ fileList.$el.find('.column-mtime .sort-indicator').hasClass('hidden')
).toEqual(false);
expect(
- fileList.$el.find('.column-mtime .sort-indicator').hasClass(ASC_CLASS)
+ fileList.$el.find('.column-mtime .sort-indicator').hasClass(DESC_CLASS)
).toEqual(true);
});
it('Uses correct sort comparator when inserting files', function() {
testFiles.sort(OCA.Files.FileList.Comparators.size);
+ testFiles.reverse(); //default is descending
// this will make it reload the testFiles with the correct sorting
fileList.$el.find('.column-size .columntitle').click();
expect(fakeServer.requests.length).toEqual(1);
@@ -1764,17 +1778,16 @@ describe('OCA.Files.FileList tests', function() {
etag: '999'
};
fileList.add(newFileData);
+ expect(fileList.findFileEl('Three.pdf').index()).toEqual(0);
+ expect(fileList.findFileEl('new file.txt').index()).toEqual(1);
+ expect(fileList.findFileEl('Two.jpg').index()).toEqual(2);
+ expect(fileList.findFileEl('somedir').index()).toEqual(3);
+ expect(fileList.findFileEl('One.txt').index()).toEqual(4);
expect(fileList.files.length).toEqual(5);
expect(fileList.$fileList.find('tr').length).toEqual(5);
- expect(fileList.findFileEl('One.txt').index()).toEqual(0);
- expect(fileList.findFileEl('somedir').index()).toEqual(1);
- expect(fileList.findFileEl('Two.jpg').index()).toEqual(2);
- expect(fileList.findFileEl('new file.txt').index()).toEqual(3);
- expect(fileList.findFileEl('Three.pdf').index()).toEqual(4);
});
it('Uses correct reversed sort comparator when inserting files', function() {
testFiles.sort(OCA.Files.FileList.Comparators.size);
- testFiles.reverse();
// this will make it reload the testFiles with the correct sorting
fileList.$el.find('.column-size .columntitle').click();
expect(fakeServer.requests.length).toEqual(1);
@@ -1811,13 +1824,13 @@ describe('OCA.Files.FileList tests', function() {
etag: '999'
};
fileList.add(newFileData);
+ expect(fileList.findFileEl('One.txt').index()).toEqual(0);
+ expect(fileList.findFileEl('somedir').index()).toEqual(1);
+ expect(fileList.findFileEl('Two.jpg').index()).toEqual(2);
+ expect(fileList.findFileEl('new file.txt').index()).toEqual(3);
+ expect(fileList.findFileEl('Three.pdf').index()).toEqual(4);
expect(fileList.files.length).toEqual(5);
expect(fileList.$fileList.find('tr').length).toEqual(5);
- expect(fileList.findFileEl('One.txt').index()).toEqual(4);
- expect(fileList.findFileEl('somedir').index()).toEqual(3);
- expect(fileList.findFileEl('Two.jpg').index()).toEqual(2);
- expect(fileList.findFileEl('new file.txt').index()).toEqual(1);
- expect(fileList.findFileEl('Three.pdf').index()).toEqual(0);
});
});
/**
diff --git a/apps/files_encryption/hooks/hooks.php b/apps/files_encryption/hooks/hooks.php
index c40fc43f7d5..4a257f2ad33 100644
--- a/apps/files_encryption/hooks/hooks.php
+++ b/apps/files_encryption/hooks/hooks.php
@@ -419,21 +419,51 @@ class Hooks {
$mp1 = $view->getMountPoint('/' . $user . '/files/' . $params['oldpath']);
$mp2 = $view->getMountPoint('/' . $user . '/files/' . $params['newpath']);
+ $type = $view->is_dir('/' . $user . '/files/' . $params['oldpath']) ? 'folder' : 'file';
+
if ($mp1 === $mp2) {
self::$renamedFiles[$params['oldpath']] = array(
'uid' => $ownerOld,
- 'path' => $pathOld);
+ 'path' => $pathOld,
+ 'type' => $type,
+ 'operation' => 'rename',
+ );
+
}
}
/**
- * after a file is renamed, rename its keyfile and share-keys also fix the file size and fix also the sharing
- * @param array $params array with oldpath and newpath
+ * mark file as renamed so that we know the original source after the file was renamed
+ * @param array $params with the old path and the new path
+ */
+ public static function preCopy($params) {
+ $user = \OCP\User::getUser();
+ $view = new \OC\Files\View('/');
+ $util = new Util($view, $user);
+ list($ownerOld, $pathOld) = $util->getUidAndFilename($params['oldpath']);
+
+ // we only need to rename the keys if the rename happens on the same mountpoint
+ // otherwise we perform a stream copy, so we get a new set of keys
+ $mp1 = $view->getMountPoint('/' . $user . '/files/' . $params['oldpath']);
+ $mp2 = $view->getMountPoint('/' . $user . '/files/' . $params['newpath']);
+
+ $type = $view->is_dir('/' . $user . '/files/' . $params['oldpath']) ? 'folder' : 'file';
+
+ if ($mp1 === $mp2) {
+ self::$renamedFiles[$params['oldpath']] = array(
+ 'uid' => $ownerOld,
+ 'path' => $pathOld,
+ 'type' => $type,
+ 'operation' => 'copy');
+ }
+ }
+
+ /**
+ * after a file is renamed/copied, rename/copy its keyfile and share-keys also fix the file size and fix also the sharing
*
- * This function is connected to the rename signal of OC_Filesystem and adjust the name and location
- * of the stored versions along the actual file
+ * @param array $params array with oldpath and newpath
*/
- public static function postRename($params) {
+ public static function postRenameOrCopy($params) {
if (\OCP\App::isEnabled('files_encryption') === false) {
return true;
@@ -451,6 +481,8 @@ class Hooks {
isset(self::$renamedFiles[$params['oldpath']]['path'])) {
$ownerOld = self::$renamedFiles[$params['oldpath']]['uid'];
$pathOld = self::$renamedFiles[$params['oldpath']]['path'];
+ $type = self::$renamedFiles[$params['oldpath']]['type'];
+ $operation = self::$renamedFiles[$params['oldpath']]['operation'];
unset(self::$renamedFiles[$params['oldpath']]);
} else {
\OCP\Util::writeLog('Encryption library', "can't get path and owner from the file before it was renamed", \OCP\Util::DEBUG);
@@ -485,8 +517,7 @@ class Hooks {
}
// handle share keys
- if (!$view->is_dir($oldKeyfilePath)) {
- $type = 'file';
+ if ($type === 'file') {
$oldKeyfilePath .= '.key';
$newKeyfilePath .= '.key';
@@ -494,18 +525,17 @@ class Hooks {
$matches = Helper::findShareKeys($oldShareKeyPath, $view);
foreach ($matches as $src) {
$dst = \OC\Files\Filesystem::normalizePath(str_replace($pathOld, $pathNew, $src));
- $view->rename($src, $dst);
+ $view->$operation($src, $dst);
}
} else {
- $type = "folder";
// handle share-keys folders
- $view->rename($oldShareKeyPath, $newShareKeyPath);
+ $view->$operation($oldShareKeyPath, $newShareKeyPath);
}
// Rename keyfile so it isn't orphaned
if ($view->file_exists($oldKeyfilePath)) {
- $view->rename($oldKeyfilePath, $newKeyfilePath);
+ $view->$operation($oldKeyfilePath, $newKeyfilePath);
}
diff --git a/apps/files_encryption/lib/helper.php b/apps/files_encryption/lib/helper.php
index fed0788028f..ed42cec326a 100755
--- a/apps/files_encryption/lib/helper.php
+++ b/apps/files_encryption/lib/helper.php
@@ -62,7 +62,9 @@ class Helper {
public static function registerFilesystemHooks() {
\OCP\Util::connectHook('OC_Filesystem', 'rename', 'OCA\Encryption\Hooks', 'preRename');
- \OCP\Util::connectHook('OC_Filesystem', 'post_rename', 'OCA\Encryption\Hooks', 'postRename');
+ \OCP\Util::connectHook('OC_Filesystem', 'post_rename', 'OCA\Encryption\Hooks', 'postRenameOrCopy');
+ \OCP\Util::connectHook('OC_Filesystem', 'copy', 'OCA\Encryption\Hooks', 'preCopy');
+ \OCP\Util::connectHook('OC_Filesystem', 'post_copy', 'OCA\Encryption\Hooks', 'postRenameOrCopy');
\OCP\Util::connectHook('OC_Filesystem', 'post_delete', 'OCA\Encryption\Hooks', 'postDelete');
\OCP\Util::connectHook('OC_Filesystem', 'delete', 'OCA\Encryption\Hooks', 'preDelete');
\OCP\Util::connectHook('OC_Filesystem', 'post_umount', 'OCA\Encryption\Hooks', 'postUmount');
diff --git a/apps/files_encryption/settings-admin.php b/apps/files_encryption/settings-admin.php
index 88e06613997..496a7cffb50 100644
--- a/apps/files_encryption/settings-admin.php
+++ b/apps/files_encryption/settings-admin.php
@@ -12,8 +12,11 @@ $tmpl = new OCP\Template('files_encryption', 'settings-admin');
// Check if an adminRecovery account is enabled for recovering files after lost pwd
$recoveryAdminEnabled = \OC::$server->getAppConfig()->getValue('files_encryption', 'recoveryAdminEnabled', '0');
+$session = new \OCA\Encryption\Session(new \OC\Files\View('/'));
+$initStatus = $session->getInitialized();
$tmpl->assign('recoveryEnabled', $recoveryAdminEnabled);
+$tmpl->assign('initStatus', $initStatus);
\OCP\Util::addscript('files_encryption', 'settings-admin');
\OCP\Util::addscript('core', 'multiselect');
diff --git a/apps/files_encryption/templates/settings-admin.php b/apps/files_encryption/templates/settings-admin.php
index d4e6abf004a..a97261dc1c9 100644
--- a/apps/files_encryption/templates/settings-admin.php
+++ b/apps/files_encryption/templates/settings-admin.php
@@ -1,6 +1,9 @@
<form id="encryption" class="section">
<h2><?php p($l->t('Encryption')); ?></h2>
+ <?php if($_["initStatus"] === \OCA\Encryption\Session::NOT_INITIALIZED): ?>
+ <?php p($l->t("Encryption App is enabled but your keys are not initialized, please log-out and log-in again")); ?>
+ <?php else: ?>
<p>
<?php p($l->t("Enable recovery key (allow to recover users files in case of password loss):")); ?>
<br/>
@@ -57,4 +60,5 @@
</button>
<span class="msg"></span>
</p>
+ <?php endif; ?>
</form>
diff --git a/apps/files_encryption/templates/settings-personal.php b/apps/files_encryption/templates/settings-personal.php
index e9988df3275..3d44b9fa9a5 100644
--- a/apps/files_encryption/templates/settings-personal.php
+++ b/apps/files_encryption/templates/settings-personal.php
@@ -1,7 +1,11 @@
<form id="encryption" class="section">
<h2><?php p( $l->t( 'Encryption' ) ); ?></h2>
- <?php if ( $_["initialized"] === '1' ): ?>
+ <?php if ( $_["initialized"] === \OCA\Encryption\Session::NOT_INITIALIZED ): ?>
+
+ <?php p($l->t("Encryption App is enabled but your keys are not initialized, please log-out and log-in again")); ?>
+
+ <?php elseif ( $_["initialized"] === \OCA\Encryption\Session::INIT_EXECUTED ): ?>
<p>
<a name="changePKPasswd" />
<label for="changePrivateKeyPasswd">
@@ -33,9 +37,8 @@
</button>
<span class="msg"></span>
</p>
- <?php endif; ?>
- <?php if ( $_["recoveryEnabled"] && $_["privateKeySet"] ): ?>
+ <?php elseif ( $_["recoveryEnabled"] && $_["privateKeySet"] && $_["initialized"] === \OCA\Encryption\Session::INIT_SUCCESSFUL ): ?>
<br />
<p>
<label for="userEnableRecovery"><?php p( $l->t( "Enable password recovery:" ) ); ?></label>
diff --git a/apps/files_encryption/tests/hooks.php b/apps/files_encryption/tests/hooks.php
index 5eda8df01b9..cc5b6d5b6f6 100644
--- a/apps/files_encryption/tests/hooks.php
+++ b/apps/files_encryption/tests/hooks.php
@@ -336,6 +336,58 @@ class Test_Encryption_Hooks extends \PHPUnit_Framework_TestCase {
}
/**
+ * test rename operation
+ */
+ function testCopyHook() {
+
+ // save file with content
+ $cryptedFile = file_put_contents('crypt:///' . self::TEST_ENCRYPTION_HOOKS_USER1 . '/files/' . $this->filename, $this->data);
+
+ // test that data was successfully written
+ $this->assertTrue(is_int($cryptedFile));
+
+ // check if keys exists
+ $this->assertTrue($this->rootView->file_exists(
+ '/' . self::TEST_ENCRYPTION_HOOKS_USER1 . '/files_encryption/share-keys/'
+ . $this->filename . '.' . self::TEST_ENCRYPTION_HOOKS_USER1 . '.shareKey'));
+
+ $this->assertTrue($this->rootView->file_exists(
+ '/' . self::TEST_ENCRYPTION_HOOKS_USER1 . '/files_encryption/keyfiles/'
+ . $this->filename . '.key'));
+
+ // make subfolder and sub-subfolder
+ $this->rootView->mkdir('/' . self::TEST_ENCRYPTION_HOOKS_USER1 . '/files/' . $this->folder);
+ $this->rootView->mkdir('/' . self::TEST_ENCRYPTION_HOOKS_USER1 . '/files/' . $this->folder . '/' . $this->folder);
+
+ $this->assertTrue($this->rootView->is_dir('/' . self::TEST_ENCRYPTION_HOOKS_USER1 . '/files/' . $this->folder . '/' . $this->folder));
+
+ // copy the file to the sub-subfolder
+ \OC\Files\Filesystem::copy($this->filename, '/' . $this->folder . '/' . $this->folder . '/' . $this->filename);
+
+ $this->assertTrue($this->rootView->file_exists('/' . self::TEST_ENCRYPTION_HOOKS_USER1 . '/files/' . $this->filename));
+ $this->assertTrue($this->rootView->file_exists('/' . self::TEST_ENCRYPTION_HOOKS_USER1 . '/files/' . $this->folder . '/' . $this->folder . '/' . $this->filename));
+
+ // keys should be copied too
+ $this->assertTrue($this->rootView->file_exists(
+ '/' . self::TEST_ENCRYPTION_HOOKS_USER1 . '/files_encryption/share-keys/'
+ . $this->filename . '.' . self::TEST_ENCRYPTION_HOOKS_USER1 . '.shareKey'));
+ $this->assertTrue($this->rootView->file_exists(
+ '/' . self::TEST_ENCRYPTION_HOOKS_USER1 . '/files_encryption/keyfiles/'
+ . $this->filename . '.key'));
+
+ $this->assertTrue($this->rootView->file_exists(
+ '/' . self::TEST_ENCRYPTION_HOOKS_USER1 . '/files_encryption/share-keys/' . $this->folder . '/' . $this->folder . '/'
+ . $this->filename . '.' . self::TEST_ENCRYPTION_HOOKS_USER1 . '.shareKey'));
+ $this->assertTrue($this->rootView->file_exists(
+ '/' . self::TEST_ENCRYPTION_HOOKS_USER1 . '/files_encryption/keyfiles/' . $this->folder . '/' . $this->folder . '/'
+ . $this->filename . '.key'));
+
+ // cleanup
+ $this->rootView->unlink('/' . self::TEST_ENCRYPTION_HOOKS_USER1 . '/files/' . $this->folder);
+ $this->rootView->unlink('/' . self::TEST_ENCRYPTION_HOOKS_USER1 . '/files/' . $this->filename);
+ }
+
+ /**
* @brief replacing encryption keys during password change should be allowed
* until the user logged in for the first time
*/
diff --git a/apps/files_sharing/ajax/publicpreview.php b/apps/files_sharing/ajax/publicpreview.php
index 0b2af7a6e59..f5343a7ef26 100644
--- a/apps/files_sharing/ajax/publicpreview.php
+++ b/apps/files_sharing/ajax/publicpreview.php
@@ -70,10 +70,6 @@ if(substr($path, 0, 1) === '/') {
$path = substr($path, 1);
}
-if ($keepAspect === true) {
- $maxY = $maxX;
-}
-
if($maxX === 0 || $maxY === 0) {
\OC_Response::setStatus(\OC_Response::STATUS_BAD_REQUEST);
\OC_Log::write('core-preview', 'x and/or y set to 0', \OC_Log::DEBUG);
diff --git a/apps/files_sharing/appinfo/update.php b/apps/files_sharing/appinfo/update.php
index fc547ba349d..72acdbac736 100644
--- a/apps/files_sharing/appinfo/update.php
+++ b/apps/files_sharing/appinfo/update.php
@@ -32,6 +32,7 @@ function updateFilePermissions($chunkSize = 99) {
}
}
+ $connection = \OC_DB::getConnection();
$chunkedPermissionList = array_chunk($updatedRows, $chunkSize, true);
foreach ($chunkedPermissionList as $subList) {
@@ -39,7 +40,7 @@ function updateFilePermissions($chunkSize = 99) {
//update share table
$ids = implode(',', array_keys($subList));
foreach ($subList as $id => $permission) {
- $statement .= "WHEN " . $id . " THEN " . $permission . " ";
+ $statement .= "WHEN " . $connection->quote($id, \PDO::PARAM_INT) . " THEN " . $permission . " ";
}
$statement .= ' END WHERE `id` IN (' . $ids . ')';
@@ -95,6 +96,7 @@ function removeSharedFolder($mkdirs = true, $chunkSize = 99) {
}
$chunkedShareList = array_chunk($shares, $chunkSize, true);
+ $connection = \OC_DB::getConnection();
foreach ($chunkedShareList as $subList) {
@@ -102,7 +104,7 @@ function removeSharedFolder($mkdirs = true, $chunkSize = 99) {
//update share table
$ids = implode(',', array_keys($subList));
foreach ($subList as $id => $target) {
- $statement .= "WHEN " . $id . " THEN '/Shared" . $target . "' ";
+ $statement .= "WHEN " . $connection->quote($id, \PDO::PARAM_INT) . " THEN " . $connection->quote('/Shared' . $target, \PDO::PARAM_STR);
}
$statement .= ' END WHERE `id` IN (' . $ids . ')';
diff --git a/apps/files_sharing/js/sharedfilelist.js b/apps/files_sharing/js/sharedfilelist.js
index d5c65a6c681..7a43185a2d7 100644
--- a/apps/files_sharing/js/sharedfilelist.js
+++ b/apps/files_sharing/js/sharedfilelist.js
@@ -59,6 +59,9 @@
$tr.attr('data-share-id', _.pluck(fileData.shares, 'id').join(','));
if (this._sharedWithUser) {
$tr.attr('data-share-owner', fileData.shareOwner);
+ $tr.attr('data-mounttype', 'shared-root');
+ var permission = parseInt($tr.attr('data-permissions')) | OC.PERMISSION_DELETE;
+ $tr.attr('data-permissions', permission);
}
return $tr;
},
@@ -162,7 +165,6 @@
else {
file.type = 'file';
if (share.isPreviewAvailable) {
- file.icon = true;
file.isPreviewAvailable = true;
}
}
diff --git a/apps/files_sharing/lib/api.php b/apps/files_sharing/lib/api.php
index 50ba74f5beb..faf141db25f 100644
--- a/apps/files_sharing/lib/api.php
+++ b/apps/files_sharing/lib/api.php
@@ -339,6 +339,8 @@ class Api {
return self::updatePassword($share, $params);
} elseif (isset($params['_put']['publicUpload'])) {
return self::updatePublicUpload($share, $params);
+ } elseif (isset($params['_put']['expireDate'])) {
+ return self::updateExpireDate($share, $params);
}
} catch (\Exception $e) {
@@ -409,7 +411,7 @@ class Api {
if ($share['item_type'] !== 'folder' ||
(int)$share['share_type'] !== \OCP\Share::SHARE_TYPE_LINK ) {
- return new \OC_OCS_Result(null, 404, "public upload is only possible for public shared folders");
+ return new \OC_OCS_Result(null, 400, "public upload is only possible for public shared folders");
}
// read, create, update (7) if public upload is enabled or
@@ -421,6 +423,29 @@ class Api {
}
/**
+ * set expire date for public link share
+ * @param array $share information about the share
+ * @param array $params contains 'expireDate' which needs to be a well formated date string, e.g DD-MM-YYYY
+ * @return \OC_OCS_Result
+ */
+ private static function updateExpireDate($share, $params) {
+ // only public links can have a expire date
+ if ((int)$share['share_type'] !== \OCP\Share::SHARE_TYPE_LINK ) {
+ return new \OC_OCS_Result(null, 400, "expire date only exists for public link shares");
+ }
+
+ try {
+ $expireDateSet = \OCP\Share::setExpirationDate($share['item_type'], $share['item_source'], $params['_put']['expireDate'], (int)$share['stime']);
+ $result = ($expireDateSet) ? new \OC_OCS_Result() : new \OC_OCS_Result(null, 404, "couldn't set expire date");
+ } catch (\Exception $e) {
+ $result = new \OC_OCS_Result(null, 404, $e->getMessage());
+ }
+
+ return $result;
+
+ }
+
+ /**
* update password for public link share
* @param array $share information about the share
* @param array $params 'password'
@@ -555,7 +580,7 @@ class Api {
* @return array with: item_source, share_type, share_with, item_type, permissions
*/
private static function getShareFromId($shareID) {
- $sql = 'SELECT `file_source`, `item_source`, `share_type`, `share_with`, `item_type`, `permissions` FROM `*PREFIX*share` WHERE `id` = ?';
+ $sql = 'SELECT `file_source`, `item_source`, `share_type`, `share_with`, `item_type`, `permissions`, `stime` FROM `*PREFIX*share` WHERE `id` = ?';
$args = array($shareID);
$query = \OCP\DB::prepare($sql);
$result = $query->execute($args);
diff --git a/apps/files_sharing/lib/external/storage.php b/apps/files_sharing/lib/external/storage.php
index 3a0de51192e..855be2872b5 100644
--- a/apps/files_sharing/lib/external/storage.php
+++ b/apps/files_sharing/lib/external/storage.php
@@ -49,7 +49,12 @@ class Storage extends DAV implements ISharedStorage {
$this->remote = $options['remote'];
$this->remoteUser = $options['owner'];
list($protocol, $remote) = explode('://', $this->remote);
- list($host, $root) = explode('/', $remote, 2);
+ if (strpos($remote, '/')) {
+ list($host, $root) = explode('/', $remote, 2);
+ } else {
+ $host = $remote;
+ $root = '';
+ }
$secure = $protocol === 'https';
$root = rtrim($root, '/') . '/public.php/webdav';
$this->mountPoint = $options['mountpoint'];
@@ -148,7 +153,7 @@ class Storage extends DAV implements ISharedStorage {
// ownCloud instance is gone, likely to be a temporary server configuration error
throw $e;
}
- } catch(\Exception $shareException) {
+ } catch (\Exception $shareException) {
// todo, maybe handle 403 better and ask the user for a new password
throw $e;
}
diff --git a/apps/files_sharing/templates/public.php b/apps/files_sharing/templates/public.php
index 386fa7e17cd..8406b79cf1a 100644
--- a/apps/files_sharing/templates/public.php
+++ b/apps/files_sharing/templates/public.php
@@ -42,7 +42,7 @@
</div>
<?php elseif (substr($_['mimetype'], 0, strpos($_['mimetype'], '/')) == 'video'): ?>
<div id="imgframe">
- <video tabindex="0" controls="" autoplay="">
+ <video tabindex="0" controls="" preload="none">
<source src="<?php p($_['downloadURL']); ?>" type="<?php p($_['mimetype']); ?>" />
</video>
</div>
diff --git a/apps/files_sharing/tests/api.php b/apps/files_sharing/tests/api.php
index 72dd5816ea0..49571d4c3c2 100644
--- a/apps/files_sharing/tests/api.php
+++ b/apps/files_sharing/tests/api.php
@@ -940,6 +940,78 @@ class Test_Files_Sharing_Api extends Test_Files_Sharing_Base {
/**
* @medium
+ */
+ function testUpdateShareExpireDate() {
+
+ $fileInfo = $this->view->getFileInfo($this->folder);
+
+ // 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');
+
+ $dateWithinRange = new \DateTime();
+ $dateWithinRange->add(new \DateInterval('P5D'));
+ $dateOutOfRange = new \DateTime();
+ $dateOutOfRange->add(new \DateInterval('P8D'));
+
+ $result = \OCP\Share::shareItem('folder', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_LINK,
+ null, 1);
+
+ // share was successful?
+ $this->assertTrue(is_string($result));
+
+ $items = \OCP\Share::getItemShared('file', null);
+
+ // make sure that we found a link share
+ $this->assertEquals(1, count($items));
+
+ $linkShare = reset($items);
+
+ // update expire date to a valid value
+ $params = array();
+ $params['id'] = $linkShare['id'];
+ $params['_put'] = array();
+ $params['_put']['expireDate'] = $dateWithinRange->format('Y-m-d');
+
+ $result = Share\Api::updateShare($params);
+
+ $this->assertTrue($result->succeeded());
+
+ $items = \OCP\Share::getItemShared('file', $linkShare['file_source']);
+
+ $updatedLinkShare = reset($items);
+
+ // date should be changed
+ $this->assertTrue(is_array($updatedLinkShare));
+ $this->assertEquals($dateWithinRange->format('Y-m-d') . ' 00:00:00', $updatedLinkShare['expiration']);
+
+ // update expire date to a value out of range
+ $params = array();
+ $params['id'] = $linkShare['id'];
+ $params['_put'] = array();
+ $params['_put']['expireDate'] = $dateOutOfRange->format('Y-m-d');
+
+ $result = Share\Api::updateShare($params);
+
+ $this->assertFalse($result->succeeded());
+
+ $items = \OCP\Share::getItemShared('file', $linkShare['file_source']);
+
+ $updatedLinkShare = reset($items);
+
+ // date shouldn't be changed
+ $this->assertTrue(is_array($updatedLinkShare));
+ $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');
+ \OCP\Share::unshare('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_LINK, null);
+
+ }
+
+ /**
+ * @medium
* @depends testCreateShare
*/
function testDeleteShare() {
@@ -1158,7 +1230,7 @@ class Test_Files_Sharing_Api extends Test_Files_Sharing_Base {
$result = \OCP\Share::shareItem('file', $info->getId(), \OCP\Share::SHARE_TYPE_USER, \Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER2, 31);
$this->assertTrue($result);
- $result = \OCP\Share::setExpirationDate('file', $info->getId() , $expireDate);
+ $result = \OCP\Share::setExpirationDate('file', $info->getId() , $expireDate, $now);
$this->assertTrue($result);
//manipulate stime so that both shares are older then the default expire date
diff --git a/apps/files_sharing/tests/update.php b/apps/files_sharing/tests/update.php
index 86b92b69616..d3555cc2ee3 100644
--- a/apps/files_sharing/tests/update.php
+++ b/apps/files_sharing/tests/update.php
@@ -176,6 +176,7 @@ class Test_Files_Sharing_Update_Routine extends Test_Files_Sharing_Base {
array(\OCP\Share::SHARE_TYPE_USER, 'folder', 'user2', 'admin', '/foo2'),
array(\OCP\Share::SHARE_TYPE_USER, 'file', 'user3', 'admin', '/foo3'),
array(\OCP\Share::SHARE_TYPE_USER, 'folder', 'user4', 'admin', '/foo4'),
+ array(\OCP\Share::SHARE_TYPE_USER, 'folder', 'user4', 'admin', "/foo'4"),
array(\OCP\Share::SHARE_TYPE_LINK, 'file', 'user1', 'admin', '/ShouldNotChange'),
array(\OCP\Share::SHARE_TYPE_CONTACT, 'contact', 'admin', 'user1', '/ShouldNotChange'),
diff --git a/apps/files_versions/appinfo/app.php b/apps/files_versions/appinfo/app.php
index 371162cd16f..8c517d4d0ff 100644
--- a/apps/files_versions/appinfo/app.php
+++ b/apps/files_versions/appinfo/app.php
@@ -8,9 +8,4 @@ OC::$CLASSPATH['OCA\Files_Versions\Capabilities'] = 'files_versions/lib/capabili
OCP\Util::addscript('files_versions', 'versions');
OCP\Util::addStyle('files_versions', 'versions');
-// Listen to write signals
-OCP\Util::connectHook('OC_Filesystem', 'write', "OCA\Files_Versions\Hooks", "write_hook");
-// Listen to delete and rename signals
-OCP\Util::connectHook('OC_Filesystem', 'post_delete', "OCA\Files_Versions\Hooks", "remove_hook");
-OCP\Util::connectHook('OC_Filesystem', 'delete', "OCA\Files_Versions\Hooks", "pre_remove_hook");
-OCP\Util::connectHook('OC_Filesystem', 'rename', "OCA\Files_Versions\Hooks", "rename_hook");
+\OCA\Files_Versions\Hooks::connectHooks();
diff --git a/apps/files_versions/lib/hooks.php b/apps/files_versions/lib/hooks.php
index 990f1403e8d..1a584232ba7 100644
--- a/apps/files_versions/lib/hooks.php
+++ b/apps/files_versions/lib/hooks.php
@@ -14,6 +14,16 @@ namespace OCA\Files_Versions;
class Hooks {
+ public static function connectHooks() {
+ // Listen to write signals
+ \OCP\Util::connectHook('OC_Filesystem', 'write', "OCA\Files_Versions\Hooks", "write_hook");
+ // Listen to delete and rename signals
+ \OCP\Util::connectHook('OC_Filesystem', 'post_delete', "OCA\Files_Versions\Hooks", "remove_hook");
+ \OCP\Util::connectHook('OC_Filesystem', 'delete', "OCA\Files_Versions\Hooks", "pre_remove_hook");
+ \OCP\Util::connectHook('OC_Filesystem', 'rename', "OCA\Files_Versions\Hooks", "rename_hook");
+ \OCP\Util::connectHook('OC_Filesystem', 'copy', "OCA\Files_Versions\Hooks", "copy_hook");
+ }
+
/**
* listen to write event.
*/
@@ -69,7 +79,25 @@ class Hooks {
$oldpath = $params['oldpath'];
$newpath = $params['newpath'];
if($oldpath<>'' && $newpath<>'') {
- Storage::rename( $oldpath, $newpath );
+ Storage::renameOrCopy($oldpath, $newpath, 'rename');
+ }
+ }
+ }
+
+ /**
+ * copy versions of copied files
+ * @param array $params array with oldpath and newpath
+ *
+ * This function is connected to the copy signal of OC_Filesystem and copies the
+ * the stored versions to the new location
+ */
+ public static function copy_hook($params) {
+
+ if (\OCP\App::isEnabled('files_versions')) {
+ $oldpath = $params['oldpath'];
+ $newpath = $params['newpath'];
+ if($oldpath<>'' && $newpath<>'') {
+ Storage::renameOrCopy($oldpath, $newpath, 'copy');
}
}
}
diff --git a/apps/files_versions/lib/versions.php b/apps/files_versions/lib/versions.php
index 2e048416c11..a9d51b2c58b 100644
--- a/apps/files_versions/lib/versions.php
+++ b/apps/files_versions/lib/versions.php
@@ -174,9 +174,12 @@ class Storage {
}
/**
- * rename versions of a file
+ * rename or copy versions of a file
+ * @param string $old_path
+ * @param string $new_path
+ * @param string $operation can be 'copy' or 'rename'
*/
- public static function rename($old_path, $new_path) {
+ public static function renameOrCopy($old_path, $new_path, $operation) {
list($uid, $oldpath) = self::getUidAndFilename($old_path);
list($uidn, $newpath) = self::getUidAndFilename($new_path);
$versions_view = new \OC\Files\View('/'.$uid .'/files_versions');
@@ -188,18 +191,21 @@ class Storage {
return self::store($new_path);
}
- self::expire($newpath);
-
if ( $files_view->is_dir($oldpath) && $versions_view->is_dir($oldpath) ) {
- $versions_view->rename($oldpath, $newpath);
+ $versions_view->$operation($oldpath, $newpath);
} else if ( ($versions = Storage::getVersions($uid, $oldpath)) ) {
// create missing dirs if necessary
self::createMissingDirectories($newpath, new \OC\Files\View('/'. $uidn));
foreach ($versions as $v) {
- $versions_view->rename($oldpath.'.v'.$v['version'], $newpath.'.v'.$v['version']);
+ $versions_view->$operation($oldpath.'.v'.$v['version'], $newpath.'.v'.$v['version']);
}
}
+
+ if (!$files_view->is_dir($newpath)) {
+ self::expire($newpath);
+ }
+
}
/**
@@ -254,34 +260,46 @@ class Storage {
public static function getVersions($uid, $filename, $userFullPath = '') {
$versions = array();
// fetch for old versions
- $view = new \OC\Files\View('/' . $uid . '/' . self::VERSIONS_ROOT);
+ $view = new \OC\Files\View('/' . $uid . '/');
$pathinfo = pathinfo($filename);
+ $versionedFile = $pathinfo['basename'];
- $files = $view->getDirectoryContent($pathinfo['dirname']);
+ $dir = self::VERSIONS_ROOT . '/' . $pathinfo['dirname'];
- $versionedFile = $pathinfo['basename'];
+ $dirContent = false;
+ if ($view->is_dir($dir)) {
+ $dirContent = $view->opendir($dir);
+ }
- foreach ($files as $file) {
- if ($file['type'] === 'file') {
- $pos = strrpos($file['path'], '.v');
- $currentFile = substr($file['name'], 0, strrpos($file['name'], '.v'));
- if ($currentFile === $versionedFile) {
- $version = substr($file['path'], $pos + 2);
- $key = $version . '#' . $filename;
- $versions[$key]['cur'] = 0;
- $versions[$key]['version'] = $version;
- $versions[$key]['humanReadableTimestamp'] = self::getHumanReadableTimestamp($version);
- if (empty($userFullPath)) {
- $versions[$key]['preview'] = '';
- } else {
- $versions[$key]['preview'] = \OCP\Util::linkToRoute('core_ajax_versions_preview', array('file' => $userFullPath, 'version' => $version));
+ if ($dirContent === false) {
+ return $versions;
+ }
+
+ if (is_resource($dirContent)) {
+ while (($entryName = readdir($dirContent)) !== false) {
+ if (!\OC\Files\Filesystem::isIgnoredDir($entryName)) {
+ $pathparts = pathinfo($entryName);
+ $filename = $pathparts['filename'];
+ if ($filename === $versionedFile) {
+ $pathparts = pathinfo($entryName);
+ $timestamp = substr($pathparts['extension'], 1);
+ $filename = $pathparts['filename'];
+ $key = $timestamp . '#' . $filename;
+ $versions[$key]['version'] = $timestamp;
+ $versions[$key]['humanReadableTimestamp'] = self::getHumanReadableTimestamp($timestamp);
+ if (empty($userFullPath)) {
+ $versions[$key]['preview'] = '';
+ } else {
+ $versions[$key]['preview'] = \OCP\Util::linkToRoute('core_ajax_versions_preview', array('file' => $userFullPath, 'version' => $timestamp));
+ }
+ $versions[$key]['path'] = $filename;
+ $versions[$key]['name'] = $versionedFile;
+ $versions[$key]['size'] = $view->filesize($dir . '/' . $entryName);
}
- $versions[$key]['path'] = $filename;
- $versions[$key]['name'] = $versionedFile;
- $versions[$key]['size'] = $file['size'];
}
}
+ closedir($dirContent);
}
// sort with newest version first
diff --git a/apps/files_versions/tests/versions.php b/apps/files_versions/tests/versions.php
index aa66faffcbf..03432276358 100644
--- a/apps/files_versions/tests/versions.php
+++ b/apps/files_versions/tests/versions.php
@@ -20,6 +20,7 @@
*
*/
+require_once __DIR__ . '/../appinfo/app.php';
require_once __DIR__ . '/../lib/versions.php';
/**
@@ -28,6 +29,32 @@ require_once __DIR__ . '/../lib/versions.php';
*/
class Test_Files_Versioning extends \PHPUnit_Framework_TestCase {
+ const TEST_VERSIONS_USER = 'test-versions-user';
+ const USERS_VERSIONS_ROOT = '/test-versions-user/files_versions';
+
+ private $rootView;
+
+ public static function setUpBeforeClass() {
+ // create test user
+ self::loginHelper(self::TEST_VERSIONS_USER, true);
+ }
+
+ public static function tearDownAfterClass() {
+ // cleanup test user
+ \OC_User::deleteUser(self::TEST_VERSIONS_USER);
+ }
+
+ function setUp() {
+ self::loginHelper(self::TEST_VERSIONS_USER);
+ $this->rootView = new \OC\Files\View();
+ if (!$this->rootView->file_exists(self::USERS_VERSIONS_ROOT)) {
+ $this->rootView->mkdir(self::USERS_VERSIONS_ROOT);
+ }
+ }
+
+ function tearDown() {
+ $this->rootView->deleteAll(self::USERS_VERSIONS_ROOT);
+ }
/**
* @medium
@@ -176,6 +203,87 @@ class Test_Files_Versioning extends \PHPUnit_Framework_TestCase {
);
}
+ function testRename() {
+
+ \OC\Files\Filesystem::file_put_contents("test.txt", "test file");
+
+ $t1 = time();
+ // second version is two weeks older, this way we make sure that no
+ // version will be expired
+ $t2 = $t1 - 60 * 60 * 24 * 14;
+
+ // create some versions
+ $v1 = self::USERS_VERSIONS_ROOT . '/test.txt.v' . $t1;
+ $v2 = self::USERS_VERSIONS_ROOT . '/test.txt.v' . $t2;
+ $v1Renamed = self::USERS_VERSIONS_ROOT . '/test2.txt.v' . $t1;
+ $v2Renamed = self::USERS_VERSIONS_ROOT . '/test2.txt.v' . $t2;
+
+ $this->rootView->file_put_contents($v1, 'version1');
+ $this->rootView->file_put_contents($v2, 'version2');
+
+ // execute rename hook of versions app
+ \OCA\Files_Versions\Storage::renameOrCopy("test.txt", "test2.txt", 'rename');
+
+ $this->assertFalse($this->rootView->file_exists($v1));
+ $this->assertFalse($this->rootView->file_exists($v2));
+
+ $this->assertTrue($this->rootView->file_exists($v1Renamed));
+ $this->assertTrue($this->rootView->file_exists($v2Renamed));
+
+ //cleanup
+ \OC\Files\Filesystem::unlink('test2.txt');
+ }
+
+ function testCopy() {
+
+ \OC\Files\Filesystem::file_put_contents("test.txt", "test file");
+
+ $t1 = time();
+ // second version is two weeks older, this way we make sure that no
+ // version will be expired
+ $t2 = $t1 - 60 * 60 * 24 * 14;
+
+ // create some versions
+ $v1 = self::USERS_VERSIONS_ROOT . '/test.txt.v' . $t1;
+ $v2 = self::USERS_VERSIONS_ROOT . '/test.txt.v' . $t2;
+ $v1Copied = self::USERS_VERSIONS_ROOT . '/test2.txt.v' . $t1;
+ $v2Copied = self::USERS_VERSIONS_ROOT . '/test2.txt.v' . $t2;
+
+ $this->rootView->file_put_contents($v1, 'version1');
+ $this->rootView->file_put_contents($v2, 'version2');
+
+ // execute copy hook of versions app
+ \OCA\Files_Versions\Storage::renameOrCopy("test.txt", "test2.txt", 'copy');
+
+ $this->assertTrue($this->rootView->file_exists($v1));
+ $this->assertTrue($this->rootView->file_exists($v2));
+
+ $this->assertTrue($this->rootView->file_exists($v1Copied));
+ $this->assertTrue($this->rootView->file_exists($v2Copied));
+
+ //cleanup
+ \OC\Files\Filesystem::unlink('test.txt');
+ \OC\Files\Filesystem::unlink('test2.txt');
+ }
+
+ /**
+ * @param string $user
+ * @param bool $create
+ * @param bool $password
+ */
+ public static function loginHelper($user, $create = false) {
+
+ if ($create) {
+ \OC_User::createUser($user, $user);
+ }
+
+ \OC_Util::tearDownFS();
+ \OC_User::setUserId('');
+ \OC\Files\Filesystem::tearDown();
+ \OC_User::setUserId($user);
+ \OC_Util::setupFS($user);
+ }
+
}
// extend the original class to make it possible to test protected methods
diff --git a/core/ajax/preview.php b/core/ajax/preview.php
index d38043707ac..edbd41d2db4 100644
--- a/core/ajax/preview.php
+++ b/core/ajax/preview.php
@@ -21,10 +21,6 @@ if ($file === '') {
exit;
}
-if ($keepAspect === true) {
- $maxY = $maxX;
-}
-
if ($maxX === 0 || $maxY === 0) {
//400 Bad Request
\OC_Response::setStatus(400);
diff --git a/core/ajax/share.php b/core/ajax/share.php
index be72e36541a..4b5a6cd664f 100644
--- a/core/ajax/share.php
+++ b/core/ajax/share.php
@@ -80,18 +80,12 @@ if (isset($_POST['action']) && isset($_POST['itemType']) && isset($_POST['itemSo
break;
case 'setExpirationDate':
if (isset($_POST['date'])) {
- $l = OC_L10N::get('core');
- $date = new \DateTime($_POST['date']);
- $today = new \DateTime('now');
-
-
-
- if ($date < $today) {
- OC_JSON::error(array('data' => array('message' => $l->t('Expiration date is in the past.'))));
- return;
+ try {
+ $return = OCP\Share::setExpirationDate($_POST['itemType'], $_POST['itemSource'], $_POST['date']);
+ ($return) ? OC_JSON::success() : OC_JSON::error();
+ } catch (\Exception $e) {
+ OC_JSON::error(array('data' => array('message' => $e->getMessage())));
}
- $return = OCP\Share::setExpirationDate($_POST['itemType'], $_POST['itemSource'], $_POST['date']);
- ($return) ? OC_JSON::success() : OC_JSON::error();
}
break;
case 'informRecipients':
diff --git a/core/css/header.css b/core/css/header.css
index 86db48a3f08..2df8cdd3aa3 100644
--- a/core/css/header.css
+++ b/core/css/header.css
@@ -190,6 +190,8 @@
#navigation .app-icon {
margin: 0 auto;
padding: 0;
+ max-height: 32px;
+ max-width: 32px;
}
/* Apps management */
diff --git a/core/css/icons.css b/core/css/icons.css
index 60f0b1b8c60..534c1c66514 100644
--- a/core/css/icons.css
+++ b/core/css/icons.css
@@ -136,6 +136,9 @@
.icon-search {
background-image: url('../img/actions/search.svg');
}
+.icon-search-white {
+ background-image: url('../img/actions/search-white.svg');
+}
.icon-settings {
background-image: url('../img/actions/settings.svg');
diff --git a/core/css/mobile.css b/core/css/mobile.css
index 6e2172ddbb7..21090d08cb7 100644
--- a/core/css/mobile.css
+++ b/core/css/mobile.css
@@ -31,16 +31,22 @@
/* compress search box on mobile, expand when focused */
.searchbox input[type="search"] {
- width: 15%;
- -webkit-transition: width 100ms;
- -moz-transition: width 100ms;
- -o-transition: width 100ms;
- transition: width 100ms;
+ width: 0;
+ cursor: pointer;
+ background-color: transparent;
+ background-image: url('../img/actions/search-white.svg');
+ -webkit-transition: all 100ms;
+ -moz-transition: all 100ms;
+ -o-transition: all 100ms;
+ transition: all 100ms;
}
.searchbox input[type="search"]:focus,
.searchbox input[type="search"]:active {
width: 155px;
max-width: 50%;
+ cursor: text;
+ background-color: #fff;
+ background-image: url('../img/actions/search.svg');
}
/* do not show display name on mobile when profile picture is present */
diff --git a/core/css/styles.css b/core/css/styles.css
index 40c1622ca26..3390b3000e2 100644
--- a/core/css/styles.css
+++ b/core/css/styles.css
@@ -444,13 +444,15 @@ input[name='password-clone'] {
.groupbottom {
position: relative;
}
-#body-login .grouptop input {
+#body-login .grouptop input,
+.grouptop input {
margin-bottom: 0;
border-bottom: 0;
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
}
-#body-login .groupmiddle input {
+#body-login .groupmiddle input,
+.groupmiddle input {
margin-top: 0;
margin-bottom: 0;
border-top: 0;
@@ -458,7 +460,8 @@ input[name='password-clone'] {
border-radius: 0;
box-shadow: 0 1px 0 rgba(0,0,0,.1) inset !important;
}
-#body-login .groupbottom input {
+#body-login .groupbottom input,
+.groupbottom input {
margin-top: 0;
border-top: 0;
border-top-right-radius: 0;
@@ -677,19 +680,33 @@ label.infield {
.center { text-align:center; }
.inlineblock { display: inline-block; }
-#notification-container { position: fixed; top: 0px; width: 100%; text-align: center; z-index: 101; line-height: 1.2;}
+#notification-container {
+ position: absolute;
+ top: 0;
+ width: 100%;
+ text-align: center;
+}
#notification, #update-notification {
+ margin: 0 auto;
+ max-width: 60%;
z-index: 101;
background-color: #fc4;
border: 0;
- padding: 0 .7em .3em;
+ padding: 1px 8px;
display: none;
position: relative;
top: 0;
border-bottom-left-radius: 3px;
border-bottom-right-radius: 3px;
+ -ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=90)";
+ filter:alpha(opacity=90);
+ opacity: .9;
+}
+#notification span, #update-notification span {
+ cursor: pointer;
+ font-weight: bold;
+ margin-left: 1em;
}
-#notification span, #update-notification span { cursor:pointer; font-weight:bold; margin-left:1em; }
tr .action:not(.permanent), .selectedActions a { -ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; filter:alpha(opacity=0); opacity:0; }
tr:hover .action, tr .action.permanent, .selectedActions a { -ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=50)"; filter:alpha(opacity=50); opacity:.5; }
diff --git a/core/img/actions/public.png b/core/img/actions/public.png
index 077bb7504de..772838ad205 100644
--- a/core/img/actions/public.png
+++ b/core/img/actions/public.png
Binary files differ
diff --git a/core/img/actions/public.svg b/core/img/actions/public.svg
index c70a7627788..99a71c6cb5b 100644
--- a/core/img/actions/public.svg
+++ b/core/img/actions/public.svg
@@ -1,4 +1,7 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<svg xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="16" width="16" version="1.0" xmlns:cc="http://creativecommons.org/ns#" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:dc="http://purl.org/dc/elements/1.1/">
- <path d="m8 1c-3.866 0-7 3.134-7 7s3.134 7 7 7 7-3.134 7-7-3.134-7-7-7zm0.80208 0.89323c1.2011 0.026708 2.2625 0.74821 3.3359 1.2214l1.732 2.3971-0.274 1.03 0.529 0.3281-0.009 1.2213c-0.0121 0.34937 0.005 0.69921-0.0091 1.0482-0.16635 0.66235-0.55063 1.2666-0.875 1.8685-0.21989 0.10841 0.02005-0.7185-0.11849-0.97526 0.032-0.5934-0.471-0.566-0.811-0.2364-0.421 0.2454-1.346 0.3194-1.376-0.3464-0.239-0.8001-0.035-1.6526 0.291-2.3971l-0.537-0.6563 0.191-1.6862-0.857-0.8658 0.201-0.948-1.0028-0.5651c-0.1977-0.1552-0.5738-0.2166-0.6563-0.4284 0.0814-0.0046 0.166-0.0109 0.2461-0.0091zm-2.4609 0.00912c0.031442 0.00459 0.069992 0.026431 0.1276 0.072917 0.338 0.1857-0.0825 0.3964-0.1823 0.5925-0.5398 0.3651 0.166 0.6641 0.401 0.957 0.3767-0.1082 0.7535-0.6467 1.3034-0.483 0.7034-0.2195 0.5913 0.5891 0.9935 0.9479 0.0522 0.1689 0.88 0.7185 0.3828 0.5377-0.4095-0.3174-0.8649-0.2935-1.1576 0.1641-0.7909 0.4286-0.3228-0.8252-0.7018-1.1302-0.5729-0.6392-0.3328 0.4775-0.401 0.8112-0.3725-0.0081-1.0681-0.2866-1.4492 0.1641l0.3736 0.6106 0.4467-0.6836c0.1085-0.2474 0.2447 0.1923 0.3645 0.2735 0.1431 0.2759 0.823 0.7434 0.3099 0.875-0.7606 0.4219-1.3589 1.0618-2.0052 1.6315-0.218 0.46-0.663 0.4074-0.9388 0.0273-0.6672-0.4105-0.6177 0.6566-0.5833 1.0573l0.58333-0.36458v0.60156c-0.0165 0.1138-0.0024 0.2322-0.0091 0.3464-0.4087 0.427-0.8207-0.5995-1.1758-0.8295l-0.0273-1.5039c0.0129-0.4225-0.0763-0.8551 0.0091-1.2669 0.8038-0.8625 1.6202-1.7561 2.0964-2.8529h0.78385c0.5478 0.2654 0.2357-0.5881 0.4557-0.556zm-1.1576 7.8204c0.095099-0.010145 0.20328 0.011573 0.31901 0.072921 0.73794 0.10562 1.2897 0.6409 1.8776 1.0482 0.46872 0.46452 1.4828 0.31578 1.5951 1.1029-0.17061 0.85375-1.0105 1.3122-1.75 1.6133-0.1846 0.103-0.383 0.185-0.5925 0.219-0.6856 0.171-0.982-0.532-1.1211-1.058-0.3104-0.65-1.0862-1.142-0.9752-1.941 0.0182-0.397 0.235-1.0134 0.6471-1.0573z"/>
+<svg xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="16" width="16" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/">
+ <g transform="matrix(.67042 -.67042 .67042 .67042 .62542 93.143)">
+ <path style="block-progression:tb;text-indent:0;color:#000000;text-transform:none" d="m69.5-61.5c-1.9217 0-3.5 1.5783-3.5 3.5 0 0.17425 0.0062 0.33232 0.03125 0.5h2.0625c-0.053-0.156-0.094-0.323-0.094-0.5 0-0.8483 0.6517-1.5 1.5-1.5h5c0.8483 0 1.5 0.6517 1.5 1.5s-0.6517 1.5-1.5 1.5h-1.6875c-0.28733 0.79501-0.78612 1.4793-1.4375 2h3.125c1.9217 0 3.5-1.5783 3.5-3.5s-1.5783-3.5-3.5-3.5h-5z"/>
+ <path style="block-progression:tb;text-indent:0;color:#000000;text-transform:none" d="m68.5-54.5c1.9217 0 3.5-1.5783 3.5-3.5 0-0.17425-0.0062-0.33232-0.03125-0.5h-2.0625c0.053 0.156 0.094 0.323 0.094 0.5 0 0.8483-0.6517 1.5-1.5 1.5h-5c-0.8483 0-1.5-0.6517-1.5-1.5s0.6517-1.5 1.5-1.5h1.6875c0.28733-0.79501 0.78612-1.4793 1.4375-2h-3.125c-1.9217 0-3.5 1.5783-3.5 3.5s1.5783 3.5 3.5 3.5h5z"/>
+ </g>
</svg>
diff --git a/core/img/actions/search-white.png b/core/img/actions/search-white.png
new file mode 100644
index 00000000000..9812c44a3d6
--- /dev/null
+++ b/core/img/actions/search-white.png
Binary files differ
diff --git a/core/img/actions/search-white.svg b/core/img/actions/search-white.svg
new file mode 100644
index 00000000000..9b312d0460d
--- /dev/null
+++ b/core/img/actions/search-white.svg
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="16" width="16" version="1.0" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/">
+ <rect style="color:#000000" fill-opacity="0" height="97.986" width="163.31" y="-32.993" x="-62.897"/>
+ <path style="color:#000000" d="m6 1c-2.7614 0-5 2.2386-5 5s2.2386 5 5 5c0.98478 0 1.8823-0.28967 2.6562-0.78125l4.4688 4.625c0.09558 0.10527 0.22619 0.16452 0.375 0.15625 0.14882-0.0083 0.3031-0.07119 0.40625-0.1875l0.9375-1.0625c0.19194-0.22089 0.19549-0.53592 0-0.71875l-4.594-4.406c0.478-0.7663 0.75-1.6555 0.75-2.625 0-2.7614-2.2386-5-5-5zm0 2c1.6569 0 3 1.3431 3 3s-1.3431 3-3 3-3-1.3431-3-3 1.3431-3 3-3z" fill="#fff"/>
+</svg>
diff --git a/core/img/filetypes/folder-public.png b/core/img/filetypes/folder-public.png
index 40d8cd067bb..7f8f8e3411c 100644
--- a/core/img/filetypes/folder-public.png
+++ b/core/img/filetypes/folder-public.png
Binary files differ
diff --git a/core/img/filetypes/folder-public.svg b/core/img/filetypes/folder-public.svg
index f1f9321fd35..9516a7de59d 100644
--- a/core/img/filetypes/folder-public.svg
+++ b/core/img/filetypes/folder-public.svg
@@ -1,59 +1,62 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="32px" width="32px" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/">
<defs>
- <linearGradient id="c" x1="27.557" gradientUnits="userSpaceOnUse" y1="7.1627" gradientTransform="matrix(.89186 0 0 1.0539 3.1208 5.4125)" x2="27.557" y2="21.387">
+ <linearGradient id="p" y2="21.387" gradientUnits="userSpaceOnUse" x2="27.557" gradientTransform="matrix(.89186 0 0 1.0539 3.1208 5.4125)" y1="7.1627" x1="27.557">
<stop stop-color="#fff" offset="0"/>
<stop stop-color="#fff" stop-opacity=".23529" offset=".0097359"/>
<stop stop-color="#fff" stop-opacity=".15686" offset=".99001"/>
<stop stop-color="#fff" stop-opacity=".39216" offset="1"/>
</linearGradient>
- <linearGradient id="d" x1="22.935" gradientUnits="userSpaceOnUse" y1="49.629" gradientTransform="matrix(.74675 0 0 .65549 -1.9219 3.1676)" x2="22.809" y2="36.658">
+ <linearGradient id="o" y2="36.658" gradientUnits="userSpaceOnUse" x2="22.809" gradientTransform="matrix(.74675 0 0 .65549 -1.9219 3.1676)" y1="49.629" x1="22.935">
<stop stop-color="#0a0a0a" stop-opacity=".498" offset="0"/>
<stop stop-color="#0a0a0a" stop-opacity="0" offset="1"/>
</linearGradient>
- <linearGradient id="e" x1="35.793" gradientUnits="userSpaceOnUse" y1="17.118" gradientTransform="matrix(.64444 0 0 .64286 .53352 .89286)" x2="35.793" y2="43.761">
+ <linearGradient id="n" y2="43.761" gradientUnits="userSpaceOnUse" x2="35.793" gradientTransform="matrix(.64444 0 0 .64286 .53352 .89286)" y1="17.118" x1="35.793">
<stop stop-color="#b4cee1" offset="0"/>
<stop stop-color="#5d9fcd" offset="1"/>
</linearGradient>
- <linearGradient id="f" x1="302.86" gradientUnits="userSpaceOnUse" y1="366.65" gradientTransform="matrix(.051143 0 0 .015916 -2.49 22.299)" x2="302.86" y2="609.51">
+ <linearGradient id="m" y2="609.51" gradientUnits="userSpaceOnUse" x2="302.86" gradientTransform="matrix(.051143 0 0 .015916 -2.49 22.299)" y1="366.65" x1="302.86">
<stop stop-opacity="0" offset="0"/>
<stop offset=".5"/>
<stop stop-opacity="0" offset="1"/>
</linearGradient>
- <radialGradient id="b" gradientUnits="userSpaceOnUse" cy="486.65" cx="605.71" gradientTransform="matrix(.019836 0 0 .015916 16.388 22.299)" r="117.14">
+ <radialGradient id="q" gradientUnits="userSpaceOnUse" cy="486.65" cx="605.71" gradientTransform="matrix(.019836 0 0 .015916 16.388 22.299)" r="117.14">
<stop offset="0"/>
<stop stop-opacity="0" offset="1"/>
</radialGradient>
- <radialGradient id="a" gradientUnits="userSpaceOnUse" cy="486.65" cx="605.71" gradientTransform="matrix(-.019836 0 0 .015916 15.601 22.299)" r="117.14">
+ <radialGradient id="r" gradientUnits="userSpaceOnUse" cy="486.65" cx="605.71" gradientTransform="matrix(-.019836 0 0 .015916 15.601 22.299)" r="117.14">
<stop offset="0"/>
<stop stop-opacity="0" offset="1"/>
</radialGradient>
- <linearGradient id="g" x1="21.37" gradientUnits="userSpaceOnUse" y1="4.7324" gradientTransform="matrix(.54384 0 0 .61466 3.2689 5.0911)" x2="21.37" y2="34.143">
+ <linearGradient id="l" y2="34.143" gradientUnits="userSpaceOnUse" x2="21.37" gradientTransform="matrix(.54384 0 0 .61466 3.2689 5.0911)" y1="4.7324" x1="21.37">
<stop stop-color="#fff" offset="0"/>
<stop stop-color="#fff" stop-opacity=".23529" offset=".11063"/>
<stop stop-color="#fff" stop-opacity=".15686" offset=".99001"/>
<stop stop-color="#fff" stop-opacity=".39216" offset="1"/>
</linearGradient>
- <linearGradient id="h" x1="62.989" gradientUnits="userSpaceOnUse" y1="13" gradientTransform="matrix(.61905 0 0 .61905 -30.392 1.4286)" x2="62.989" y2="16">
+ <linearGradient id="k" y2="16" gradientUnits="userSpaceOnUse" x2="62.989" gradientTransform="matrix(.61905 0 0 .61905 -30.392 1.4286)" y1="13" x1="62.989">
<stop stop-color="#f9f9f9" offset="0"/>
<stop stop-color="#d8d8d8" offset="1"/>
</linearGradient>
- <linearGradient id="i" x1="-51.786" gradientUnits="userSpaceOnUse" x2="-51.786" gradientTransform="matrix(.50703 0 0 .503 68.029 1.3298)" y1="53.514" y2="3.6337">
+ <linearGradient id="j" y2="3.6337" gradientUnits="userSpaceOnUse" y1="53.514" gradientTransform="matrix(.50703 0 0 .503 68.029 1.3298)" x2="-51.786" x1="-51.786">
<stop stop-opacity=".32174" offset="0"/>
<stop stop-opacity=".27826" offset="1"/>
</linearGradient>
</defs>
- <path opacity=".8" style="color:#000000" d="m4.0002 6.5001c-0.43342 0.005-0.5 0.21723-0.5 0.6349v1.365c-1.2457 0-1-0.002-1 0.54389 0.0216 6.5331 0 6.9014 0 7.4561 0.90135 0 27-2.349 27-3.36v-4.0961c0-0.41767-0.34799-0.54876-0.78141-0.54389h-14.219v-1.365c0-0.41767-0.26424-0.63977-0.69767-0.6349h-9.8023z" stroke="url(#i)" fill="none"/>
- <path style="color:#000000" d="m4.0002 7v2h-1v4h26v-4h-15v-2h-10z" fill="url(#h)"/>
- <path style="color:#000000" stroke-linecap="round" d="m4.5002 7.5v2h-1v4h25v-4h-15v-2h-9z" stroke="url(#g)" fill="none"/>
+ <path opacity=".8" style="color:#000000" d="m4.0002 6.5001c-0.43342 0.005-0.5 0.21723-0.5 0.6349v1.365c-1.2457 0-1-0.002-1 0.54389 0.0216 6.5331 0 6.9014 0 7.4561 0.90135 0 27-2.349 27-3.36v-4.0961c0-0.41767-0.34799-0.54876-0.78141-0.54389h-14.219v-1.365c0-0.41767-0.26424-0.63977-0.69767-0.6349h-9.8023z" stroke="url(#j)" fill="none"/>
+ <path style="color:#000000" d="m4.0002 7v2h-1v4h26v-4h-15v-2h-10z" fill="url(#k)"/>
+ <path style="color:#000000" d="m4.5002 7.5v2h-1v4h25v-4h-15v-2h-9z" stroke="url(#l)" stroke-linecap="round" fill="none"/>
<g transform="translate(.00017936 -1)">
- <rect opacity=".3" height="3.8653" width="24.695" y="28.135" x="3.6472" fill="url(#f)"/>
- <path opacity=".3" d="m28.342 28.135v3.865c1.0215 0.0073 2.4695-0.86596 2.4695-1.9328s-1.1399-1.9323-2.4695-1.9323z" fill="url(#b)"/>
- <path opacity=".3" d="m3.6472 28.135v3.865c-1.0215 0.0073-2.4695-0.86596-2.4695-1.9328s1.1399-1.9323 2.4695-1.9323z" fill="url(#a)"/>
+ <rect opacity=".3" height="3.8653" width="24.695" y="28.135" x="3.6472" fill="url(#m)"/>
+ <path opacity=".3" d="m28.342 28.135v3.865c1.0215 0.0073 2.4695-0.86596 2.4695-1.9328s-1.1399-1.9323-2.4695-1.9323z" fill="url(#q)"/>
+ <path opacity=".3" d="m3.6472 28.135v3.865c-1.0215 0.0073-2.4695-0.86596-2.4695-1.9328s1.1399-1.9323 2.4695-1.9323z" fill="url(#r)"/>
</g>
- <path style="color:#000000" d="m1.927 11.5c-0.69105 0.0796-0.32196 0.90258-0.37705 1.3654 0.0802 0.29906 0.59771 15.718 0.59771 16.247 0 0.46018 0.22667 0.38222 0.80101 0.38222h26.397c0.61872 0.0143 0.48796 0.007 0.48796-0.38947 0.0452-0.20269 0.63993-16.978 0.66282-17.243 0-0.279 0.0581-0.3621-0.30493-0.3621h-28.265z" fill="url(#e)"/>
- <path opacity=".4" d="m1.682 13 28.636 0.00027c0.4137 0 0.68181 0.29209 0.68181 0.65523l-0.6735 17.712c0.01 0.45948-0.1364 0.64166-0.61707 0.63203l-27.256-0.0115c-0.4137 0-0.83086-0.27118-0.83086-0.63432l-0.62244-17.698c0-0.36314 0.26812-0.65549 0.68182-0.65549z" fill="url(#d)"/>
- <path opacity=".5" style="color:#000000" d="m2.5002 12.5 0.62498 16h25.749l0.62498-16z" stroke="url(#c)" stroke-linecap="round" fill="none"/>
+ <path style="color:#000000" d="m1.927 11.5c-0.69105 0.0796-0.32196 0.90258-0.37705 1.3654 0.0802 0.29906 0.59771 15.718 0.59771 16.247 0 0.46018 0.22667 0.38222 0.80101 0.38222h26.397c0.61872 0.0143 0.48796 0.007 0.48796-0.38947 0.0452-0.20269 0.63993-16.978 0.66282-17.243 0-0.279 0.0581-0.3621-0.30493-0.3621h-28.265z" fill="url(#n)"/>
+ <path opacity=".4" d="m1.682 13 28.636 0.00027c0.4137 0 0.68181 0.29209 0.68181 0.65523l-0.6735 17.712c0.01 0.45948-0.1364 0.64166-0.61707 0.63203l-27.256-0.0115c-0.4137 0-0.83086-0.27118-0.83086-0.63432l-0.62244-17.698c0-0.36314 0.26812-0.65549 0.68182-0.65549z" fill="url(#o)"/>
+ <path opacity=".5" style="color:#000000" d="m2.5002 12.5 0.62498 16h25.749l0.62498-16z" stroke="url(#p)" stroke-linecap="round" fill="none"/>
<path opacity=".3" stroke-linejoin="round" style="color:#000000" d="m1.927 11.5c-0.69105 0.0796-0.32196 0.90258-0.37705 1.3654 0.0802 0.29906 0.59771 15.718 0.59771 16.247 0 0.46018 0.22667 0.38222 0.80101 0.38222h26.397c0.61872 0.0143 0.48796 0.007 0.48796-0.38947 0.0452-0.20269 0.63993-16.978 0.66282-17.243 0-0.279 0.0581-0.3621-0.30493-0.3621h-28.265z" stroke="#000" stroke-linecap="round" fill="none"/>
- <path opacity=".7" d="m16 13c-3.866 0-7 3.134-7 7s3.134 7 7 7 7-3.134 7-7-3.134-7-7-7zm0.80208 0.89323c1.2011 0.02671 2.2625 0.74821 3.3359 1.2214l1.732 2.3971-0.274 1.03 0.529 0.3281-0.009 1.2213c-0.0121 0.34937 0.005 0.69921-0.0091 1.0482-0.16635 0.66235-0.55063 1.2666-0.875 1.8685-0.21989 0.10841 0.02005-0.7185-0.11849-0.97526 0.032-0.5934-0.471-0.566-0.811-0.2364-0.421 0.2454-1.346 0.3194-1.376-0.3464-0.239-0.8001-0.035-1.6526 0.291-2.3971l-0.537-0.6563 0.191-1.6862-0.857-0.8658 0.201-0.948-1.0028-0.5651c-0.1977-0.1552-0.5738-0.2166-0.6563-0.4284 0.0814-0.0046 0.166-0.0109 0.2461-0.0091zm-2.4609 0.0091c0.03144 0.0046 0.06999 0.02643 0.1276 0.07292 0.338 0.1857-0.0825 0.3964-0.1823 0.5925-0.5398 0.3651 0.166 0.6641 0.401 0.957 0.3767-0.1082 0.7535-0.6467 1.3034-0.483 0.7034-0.2195 0.5913 0.5891 0.9935 0.9479 0.0522 0.1689 0.88 0.7185 0.3828 0.5377-0.4095-0.3174-0.8649-0.2935-1.1576 0.1641-0.7909 0.4286-0.3228-0.8252-0.7018-1.1302-0.5729-0.6392-0.3328 0.4775-0.401 0.8112-0.3725-0.0081-1.0681-0.2866-1.4492 0.1641l0.3736 0.6106 0.4467-0.6836c0.1085-0.2474 0.2447 0.1923 0.3645 0.2735 0.1431 0.2759 0.823 0.7434 0.3099 0.875-0.7606 0.4219-1.3589 1.0618-2.0052 1.6315-0.218 0.46-0.663 0.4074-0.9388 0.0273-0.6672-0.4105-0.6177 0.6566-0.5833 1.0573l0.58333-0.36458v0.60156c-0.0165 0.1138-0.0024 0.2322-0.0091 0.3464-0.4087 0.427-0.8207-0.5995-1.1758-0.8295l-0.0273-1.5039c0.0129-0.4225-0.0763-0.8551 0.0091-1.2669 0.8038-0.8625 1.6202-1.7561 2.0964-2.8529h0.78385c0.5478 0.2654 0.2357-0.5881 0.4557-0.556zm-1.1576 7.8204c0.0951-0.01014 0.20328 0.01157 0.31901 0.07292 0.73794 0.10562 1.2897 0.6409 1.8776 1.0482 0.46872 0.46452 1.4828 0.31578 1.5951 1.1029-0.17061 0.85375-1.0105 1.3122-1.75 1.6133-0.1846 0.103-0.383 0.185-0.5925 0.219-0.6856 0.171-0.982-0.532-1.1211-1.058-0.3104-0.65-1.0862-1.142-0.9752-1.941 0.0182-0.397 0.235-1.0134 0.6471-1.0573z"/>
+ <g opacity=".7" transform="matrix(.67042 -.67042 .67042 .67042 8.6253 106.14)">
+ <path style="block-progression:tb;color:#000000;text-transform:none;text-indent:0" d="m69.5-61.5c-1.9217 0-3.5 1.5783-3.5 3.5 0 0.17425 0.0062 0.33232 0.03125 0.5h2.0625c-0.053-0.156-0.094-0.323-0.094-0.5 0-0.8483 0.6517-1.5 1.5-1.5h5c0.8483 0 1.5 0.6517 1.5 1.5s-0.6517 1.5-1.5 1.5h-1.6875c-0.28733 0.79501-0.78612 1.4793-1.4375 2h3.125c1.9217 0 3.5-1.5783 3.5-3.5s-1.5783-3.5-3.5-3.5h-5z"/>
+ <path style="block-progression:tb;color:#000000;text-transform:none;text-indent:0" d="m68.5-54.5c1.9217 0 3.5-1.5783 3.5-3.5 0-0.17425-0.0062-0.33232-0.03125-0.5h-2.0625c0.053 0.156 0.094 0.323 0.094 0.5 0 0.8483-0.6517 1.5-1.5 1.5h-5c-0.8483 0-1.5-0.6517-1.5-1.5s0.6517-1.5 1.5-1.5h1.6875c0.28733-0.79501 0.78612-1.4793 1.4375-2h-3.125c-1.9217 0-3.5 1.5783-3.5 3.5s1.5783 3.5 3.5 3.5h5z"/>
+ </g>
</svg>
diff --git a/core/js/js.js b/core/js/js.js
index 4a9a5ce82ff..60f9cc11a58 100644
--- a/core/js/js.js
+++ b/core/js/js.js
@@ -696,7 +696,7 @@ OC.Notification={
var notification = $('#notification');
if((notification.filter('span.undo').length == 1) || OC.Notification.isHidden()){
notification.html(html);
- notification.fadeIn().css("display","inline");
+ notification.fadeIn().css('display','inline-block');
}else{
OC.Notification.queuedNotifications.push(html);
}
@@ -710,7 +710,7 @@ OC.Notification={
var notification = $('#notification');
if((notification.filter('span.undo').length == 1) || OC.Notification.isHidden()){
notification.text(text);
- notification.fadeIn().css("display","inline");
+ notification.fadeIn().css('display','inline-block');
}else{
OC.Notification.queuedNotifications.push($('<div/>').text(text).html());
}
@@ -1353,6 +1353,18 @@ OC.Util = {
}
});
});
+ },
+
+ /**
+ * Remove the time component from a given date
+ *
+ * @param {Date} date date
+ * @return {Date} date with stripped time
+ */
+ stripTime: function(date) {
+ // FIXME: likely to break when crossing DST
+ // would be better to use a library like momentJS
+ return new Date(date.getFullYear(), date.getMonth(), date.getDate());
}
};
diff --git a/core/js/share.js b/core/js/share.js
index e8d486055b0..14abdf18ade 100644
--- a/core/js/share.js
+++ b/core/js/share.js
@@ -436,7 +436,7 @@ OC.Share={
}
}
if (share.expiration != null) {
- OC.Share.showExpirationDate(share.expiration);
+ OC.Share.showExpirationDate(share.expiration, share.stime);
}
});
}
@@ -716,7 +716,24 @@ OC.Share={
dirname:function(path) {
return path.replace(/\\/g,'/').replace(/\/[^\/]*$/, '');
},
- showExpirationDate:function(date) {
+ /**
+ * Displays the expiration date field
+ *
+ * @param {Date} date current expiration date
+ * @param {int} [shareTime] share timestamp in seconds, defaults to now
+ */
+ showExpirationDate:function(date, shareTime) {
+ var now = new Date();
+ var datePickerOptions = {
+ minDate: now,
+ maxDate: null
+ };
+ if (_.isNumber(shareTime)) {
+ shareTime = new Date(shareTime * 1000);
+ }
+ if (!shareTime) {
+ shareTime = now;
+ }
$('#expirationCheckbox').attr('checked', true);
$('#expirationDate').val(date);
$('#expirationDate').show('blind');
@@ -726,13 +743,14 @@ OC.Share={
});
if (oc_appconfig.core.defaultExpireDateEnforced) {
$('#expirationCheckbox').attr('disabled', true);
- $.datepicker.setDefaults({
- maxDate : new Date(date.replace(' 00:00:00', ''))
- });
+ shareTime = OC.Util.stripTime(shareTime).getTime();
+ // max date is share date + X days
+ datePickerOptions.maxDate = new Date(shareTime + oc_appconfig.core.defaultExpireDate * 24 * 3600 * 1000);
}
if(oc_appconfig.core.defaultExpireDateEnabled) {
$('#defaultExpireMessage').show('blind');
}
+ $.datepicker.setDefaults(datePickerOptions);
}
};
diff --git a/core/js/tests/specs/coreSpec.js b/core/js/tests/specs/coreSpec.js
index dd9d4a79277..166210d0312 100644
--- a/core/js/tests/specs/coreSpec.js
+++ b/core/js/tests/specs/coreSpec.js
@@ -466,6 +466,12 @@ describe('Core base tests', function() {
}
});
});
+ describe('stripTime', function() {
+ it('strips time from dates', function() {
+ expect(OC.Util.stripTime(new Date(2014, 2, 24, 15, 4, 45, 24)))
+ .toEqual(new Date(2014, 2, 24, 0, 0, 0, 0));
+ });
+ });
});
});
diff --git a/core/js/tests/specs/shareSpec.js b/core/js/tests/specs/shareSpec.js
index 00a88ba36ef..32fecf82b65 100644
--- a/core/js/tests/specs/shareSpec.js
+++ b/core/js/tests/specs/shareSpec.js
@@ -83,16 +83,6 @@ describe('OC.Share tests', function() {
expect($el.attr('data-item-source')).toEqual('123');
// TODO: expect that other parts are rendered correctly
});
- it('shows default expiration date when set', function() {
- oc_appconfig.core.defaultExpireDateEnabled = "yes";
- oc_appconfig.core.defaultExpireDate = '';
- // TODO: expect that default date was set
- });
- it('shows default expiration date is set but disabled', function() {
- oc_appconfig.core.defaultExpireDateEnabled = "no";
- oc_appconfig.core.defaultExpireDate = '';
- // TODO: expect that default date was NOT set
- });
describe('Share with link', function() {
// TODO: test ajax calls
// TODO: test password field visibility (whenever enforced or not)
@@ -265,6 +255,135 @@ describe('OC.Share tests', function() {
OC.linkTo('', 'public.php')+'?service=files&t=anothertoken';
expect($('#dropdown #linkText').val()).toEqual(link);
});
+ describe('expiration date', function() {
+ var shareData;
+ var shareItem;
+ var clock;
+
+ function showDropDown() {
+ OC.Share.showDropDown(
+ 'file',
+ 123,
+ $container,
+ 'http://localhost/dummylink',
+ 31,
+ 'folder'
+ );
+ }
+
+ beforeEach(function() {
+ // pick a fake date
+ clock = sinon.useFakeTimers(new Date(2014, 0, 20, 14, 0, 0).getTime());
+ shareItem = {
+ displayname_owner: 'root',
+ expiration: null,
+ file_source: 123,
+ file_target: '/folder',
+ id: 20,
+ item_source: '123',
+ item_type: 'folder',
+ mail_send: '0',
+ parent: null,
+ path: '/folder',
+ permissions: OC.PERMISSION_READ,
+ share_type: OC.Share.SHARE_TYPE_LINK,
+ share_with: null,
+ stime: 1403884258,
+ storage: 1,
+ token: 'tehtoken',
+ uid_owner: 'root'
+ };
+ shareData = {
+ reshare: [],
+ shares: []
+ };
+ loadItemStub.returns(shareData);
+ oc_appconfig.core.defaultExpireDate = 7;
+ oc_appconfig.core.defaultExpireDateEnabled = false;
+ oc_appconfig.core.defaultExpireDateEnforced = false;
+ });
+ afterEach(function() {
+ clock.restore();
+ });
+
+ it('does not check expiration date checkbox when no date was set', function() {
+ shareItem.expiration = null;
+ shareData.shares.push(shareItem);
+ showDropDown();
+ expect($('#dropdown [name=expirationCheckbox]').prop('checked')).toEqual(false);
+ expect($('#dropdown #expirationDate').val()).toEqual('');
+ });
+ it('does not check expiration date checkbox for new share', function() {
+ showDropDown();
+ expect($('#dropdown [name=expirationCheckbox]').prop('checked')).toEqual(false);
+ expect($('#dropdown #expirationDate').val()).toEqual('');
+ });
+ it('checks expiration date checkbox and populates field when expiration date was set', function() {
+ shareItem.expiration = 1234;
+ shareData.shares.push(shareItem);
+ showDropDown();
+ expect($('#dropdown [name=expirationCheckbox]').prop('checked')).toEqual(true);
+ expect($('#dropdown #expirationDate').val()).toEqual('1234');
+ });
+ it('sets default date when default date setting is enabled', function() {
+ /* jshint camelcase:false */
+ oc_appconfig.core.defaultExpireDateEnabled = true;
+ showDropDown();
+ $('#dropdown [name=linkCheckbox]').click();
+ // enabled by default
+ expect($('#dropdown [name=expirationCheckbox]').prop('checked')).toEqual(true);
+ // TODO: those zeros must go...
+ expect($('#dropdown #expirationDate').val()).toEqual('2014-1-27 00:00:00');
+
+ // disabling is allowed
+ $('#dropdown [name=expirationCheckbox]').click();
+ expect($('#dropdown [name=expirationCheckbox]').prop('checked')).toEqual(false);
+ });
+ it('enforces default date when enforced date setting is enabled', function() {
+ /* jshint camelcase:false */
+ oc_appconfig.core.defaultExpireDateEnabled = true;
+ oc_appconfig.core.defaultExpireDateEnforced = true;
+ showDropDown();
+ $('#dropdown [name=linkCheckbox]').click();
+ expect($('#dropdown [name=expirationCheckbox]').prop('checked')).toEqual(true);
+ // TODO: those zeros must go...
+ expect($('#dropdown #expirationDate').val()).toEqual('2014-1-27 00:00:00');
+
+ // disabling is not allowed
+ expect($('#dropdown [name=expirationCheckbox]').prop('disabled')).toEqual(true);
+ $('#dropdown [name=expirationCheckbox]').click();
+ expect($('#dropdown [name=expirationCheckbox]').prop('checked')).toEqual(true);
+ });
+ it('sets picker minDate to today and no maxDate by default', function() {
+ showDropDown();
+ $('#dropdown [name=linkCheckbox]').click();
+ $('#dropdown [name=expirationCheckbox]').click();
+ expect($.datepicker._defaults.minDate).toEqual(new Date());
+ expect($.datepicker._defaults.maxDate).toEqual(null);
+ });
+ it('limits the date range to X days after share time when enforced', function() {
+ /* jshint camelcase:false */
+ oc_appconfig.core.defaultExpireDateEnabled = true;
+ oc_appconfig.core.defaultExpireDateEnforced = true;
+ showDropDown();
+ $('#dropdown [name=linkCheckbox]').click();
+ expect($.datepicker._defaults.minDate).toEqual(new Date());
+ expect($.datepicker._defaults.maxDate).toEqual(new Date(2014, 0, 27, 0, 0, 0, 0));
+ });
+ it('limits the date range to X days after share time when enforced, even when redisplayed the next days', function() {
+ // item exists, was created two days ago
+ shareItem.expiration = '2014-1-27';
+ // share time has time component but must be stripped later
+ shareItem.stime = new Date(2014, 0, 20, 11, 0, 25).getTime() / 1000;
+ shareData.shares.push(shareItem);
+ /* jshint camelcase:false */
+ oc_appconfig.core.defaultExpireDateEnabled = true;
+ oc_appconfig.core.defaultExpireDateEnforced = true;
+ showDropDown();
+ expect($.datepicker._defaults.minDate).toEqual(new Date());
+ expect($.datepicker._defaults.maxDate).toEqual(new Date(2014, 0, 27, 0, 0, 0, 0));
+ });
+ });
});
describe('"sharesChanged" event', function() {
var autocompleteOptions;
diff --git a/core/lostpassword/controller/lostcontroller.php b/core/lostpassword/controller/lostcontroller.php
index b1be65b4f01..e4d51fde077 100644
--- a/core/lostpassword/controller/lostcontroller.php
+++ b/core/lostpassword/controller/lostcontroller.php
@@ -20,13 +20,36 @@ use \OC\Core\LostPassword\EncryptedDataException;
class LostController extends Controller {
+ /**
+ * @var \OCP\IURLGenerator
+ */
protected $urlGenerator;
+
+ /**
+ * @var \OCP\IUserManager
+ */
protected $userManager;
+
+ /**
+ * @var \OC_Defaults
+ */
protected $defaults;
+
+ /**
+ * @var IL10N
+ */
protected $l10n;
protected $from;
protected $isDataEncrypted;
+
+ /**
+ * @var IConfig
+ */
protected $config;
+
+ /**
+ * @var IUserSession
+ */
protected $userSession;
public function __construct($appName,
@@ -110,7 +133,7 @@ class LostController extends Controller {
throw new \Exception($this->l10n->t('Couldn\'t reset password because the token is invalid'));
}
- if (!$user->setPassword($userId, $password)) {
+ if (!$user->setPassword($password)) {
throw new \Exception();
}
diff --git a/cron.php b/cron.php
index 7f746911f42..4c86407b944 100644
--- a/cron.php
+++ b/cron.php
@@ -48,6 +48,11 @@ try {
require_once 'lib/base.php';
+ if (\OCP\Util::needUpgrade()) {
+ \OCP\Util::writeLog('cron', 'Update required, skipping cron', \OCP\Util::DEBUG);
+ exit();
+ }
+
// load all apps to get all api routes properly setup
OC_App::loadApps();
diff --git a/lib/base.php b/lib/base.php
index 730cee5231d..341859dc5f3 100644
--- a/lib/base.php
+++ b/lib/base.php
@@ -564,6 +564,7 @@ class OC {
self::registerPreviewHooks();
self::registerShareHooks();
self::registerLogRotate();
+ self::registerLocalAddressBook();
//make sure temporary files are cleaned up
register_shutdown_function(array('OC_Helper', 'cleanTmp'));
@@ -575,6 +576,14 @@ class OC {
}
}
+ private static function registerLocalAddressBook() {
+ self::$server->getContactsManager()->register(function() {
+ $userManager = \OC::$server->getUserManager();
+ \OC::$server->getContactsManager()->registerAddressBook(
+ new \OC\Contacts\LocalAddressBook($userManager));
+ });
+ }
+
/**
* register hooks for the cache
*/
diff --git a/lib/private/backgroundjob/joblist.php b/lib/private/backgroundjob/joblist.php
index 211d7e9abfc..9d15cd1663a 100644
--- a/lib/private/backgroundjob/joblist.php
+++ b/lib/private/backgroundjob/joblist.php
@@ -96,7 +96,10 @@ class JobList implements IJobList {
$query->execute();
$jobs = array();
while ($row = $query->fetch()) {
- $jobs[] = $this->buildJob($row);
+ $job = $this->buildJob($row);
+ if ($job) {
+ $jobs[] = $job;
+ }
}
return $jobs;
}
diff --git a/lib/private/contacts/localaddressbook.php b/lib/private/contacts/localaddressbook.php
new file mode 100644
index 00000000000..483bbee83f8
--- /dev/null
+++ b/lib/private/contacts/localaddressbook.php
@@ -0,0 +1,104 @@
+<?php
+ /**
+ * ownCloud
+ *
+ * @author Thomas Müller
+ * @copyright 2014 Thomas Müller >deepdiver@owncloud.com>
+ *
+ */
+
+namespace OC\Contacts;
+
+class LocalAddressBook implements \OCP\IAddressBook {
+
+ /**
+ * @var \OCP\IUserManager
+ */
+ private $userManager;
+
+ /**
+ * @param $userManager
+ */
+ public function __construct($userManager) {
+ $this->userManager = $userManager;
+ }
+
+ /**
+ * @return string defining the technical unique key
+ */
+ public function getKey() {
+ return 'local';
+ }
+
+ /**
+ * In comparison to getKey() this function returns a human readable (maybe translated) name
+ *
+ * @return mixed
+ */
+ public function getDisplayName() {
+ return "Local users";
+ }
+
+ /**
+ * @param string $pattern which should match within the $searchProperties
+ * @param array $searchProperties defines the properties within the query pattern should match
+ * @param array $options - for future use. One should always have options!
+ * @return array an array of contacts which are arrays of key-value-pairs
+ */
+ public function search($pattern, $searchProperties, $options) {
+ $users = array();
+ if($pattern == '') {
+ // Fetch all contacts
+ $users = $this->userManager->search('');
+ } else {
+ foreach($searchProperties as $property) {
+ $result = array();
+ if($property === 'FN') {
+ $result = $this->userManager->searchDisplayName($pattern);
+ } else if ($property === 'id') {
+ $result = $this->userManager->search($pattern);
+ }
+ if (is_array($result)) {
+ $users = array_merge($users, $result);
+ }
+ }
+ }
+
+ $contacts = array();
+ foreach($users as $user){
+ $contact = array(
+ "id" => $user->getUID(),
+ "FN" => $user->getDisplayname(),
+ "EMAIL" => array(),
+ "IMPP" => array(
+ "x-owncloud-handle:" . $user->getUID()
+ )
+ );
+ $contacts[] = $contact;
+ }
+ return $contacts;
+ }
+
+ /**
+ * @param array $properties this array if key-value-pairs defines a contact
+ * @return array an array representing the contact just created or updated
+ */
+ public function createOrUpdate($properties) {
+ return array();
+ }
+
+ /**
+ * @return int
+ */
+ public function getPermissions() {
+ return \OCP\PERMISSION_READ;
+ }
+
+ /**
+ * @param object $id the unique identifier to a contact
+ * @return bool successful or not
+ */
+ public function delete($id) {
+ return false;
+ }
+}
diff --git a/lib/private/db/mdb2schemamanager.php b/lib/private/db/mdb2schemamanager.php
index d3e379c9417..91e590a901a 100644
--- a/lib/private/db/mdb2schemamanager.php
+++ b/lib/private/db/mdb2schemamanager.php
@@ -59,7 +59,8 @@ class MDB2SchemaManager {
public function getMigrator() {
$platform = $this->conn->getDatabasePlatform();
if ($platform instanceof SqlitePlatform) {
- return new SQLiteMigrator($this->conn);
+ $config = \OC::$server->getConfig();
+ return new SQLiteMigrator($this->conn, $config);
} else if ($platform instanceof OraclePlatform) {
return new OracleMigrator($this->conn);
} else if ($platform instanceof MySqlPlatform) {
diff --git a/lib/private/db/migrator.php b/lib/private/db/migrator.php
index 6443cf4ed48..d05f8455551 100644
--- a/lib/private/db/migrator.php
+++ b/lib/private/db/migrator.php
@@ -110,7 +110,9 @@ class Migrator {
$this->dropTable($tmpName);
} catch (DBALException $e) {
// pgsql needs to commit it's failed transaction before doing anything else
- $this->connection->commit();
+ if ($this->connection->isTransactionActive()) {
+ $this->connection->commit();
+ }
$this->dropTable($tmpName);
throw new MigrationException($table->getName(), $e->getMessage());
}
diff --git a/lib/private/db/mysqlmigrator.php b/lib/private/db/mysqlmigrator.php
index 97495f52032..c0adcdf5df3 100644
--- a/lib/private/db/mysqlmigrator.php
+++ b/lib/private/db/mysqlmigrator.php
@@ -17,6 +17,10 @@ class MySQLMigrator extends Migrator {
* @return \Doctrine\DBAL\Schema\SchemaDiff
*/
protected function getDiff(Schema $targetSchema, \Doctrine\DBAL\Connection $connection) {
+ $platform = $connection->getDatabasePlatform();
+ $platform->registerDoctrineTypeMapping('enum', 'string');
+ $platform->registerDoctrineTypeMapping('bit', 'string');
+
$schemaDiff = parent::getDiff($targetSchema, $connection);
// identifiers need to be quoted for mysql
diff --git a/lib/private/db/sqlitemigrator.php b/lib/private/db/sqlitemigrator.php
index f5f78986771..94b421c5562 100644
--- a/lib/private/db/sqlitemigrator.php
+++ b/lib/private/db/sqlitemigrator.php
@@ -9,8 +9,24 @@
namespace OC\DB;
use Doctrine\DBAL\DBALException;
+use Doctrine\DBAL\Schema\Schema;
class SQLiteMigrator extends Migrator {
+
+ /**
+ * @var \OCP\IConfig
+ */
+ private $config;
+
+ /**
+ * @param \Doctrine\DBAL\Connection $connection
+ * @param \OCP\IConfig $config
+ */
+ public function __construct(\Doctrine\DBAL\Connection $connection, \OCP\IConfig $config) {
+ parent::__construct($connection);
+ $this->config = $config;
+ }
+
/**
* @param \Doctrine\DBAL\Schema\Schema $targetSchema
* @throws \OC\DB\MigrationException
@@ -19,7 +35,7 @@ class SQLiteMigrator extends Migrator {
*/
public function checkMigrate(\Doctrine\DBAL\Schema\Schema $targetSchema) {
$dbFile = $this->connection->getDatabase();
- $tmpFile = \OC_Helper::tmpFile('.db');
+ $tmpFile = $this->buildTempDatabase();
copy($dbFile, $tmpFile);
$connectionParams = array(
@@ -37,4 +53,25 @@ class SQLiteMigrator extends Migrator {
throw new MigrationException('', $e->getMessage());
}
}
+
+ /**
+ * @return string
+ */
+ private function buildTempDatabase() {
+ $dataDir = $this->config->getSystemValue("datadirectory", \OC::$SERVERROOT . '/data');
+ $tmpFile = uniqid("oc_");
+ return "$dataDir/$tmpFile.db";
+ }
+
+ /**
+ * @param Schema $targetSchema
+ * @param \Doctrine\DBAL\Connection $connection
+ * @return \Doctrine\DBAL\Schema\SchemaDiff
+ */
+ protected function getDiff(Schema $targetSchema, \Doctrine\DBAL\Connection $connection) {
+ $platform = $connection->getDatabasePlatform();
+ $platform->registerDoctrineTypeMapping('tinyint unsigned', 'integer');
+
+ return parent::getDiff($targetSchema, $connection);
+ }
}
diff --git a/lib/private/image.php b/lib/private/image.php
index 5331c399159..0dff8c5a9da 100644
--- a/lib/private/image.php
+++ b/lib/private/image.php
@@ -870,6 +870,14 @@ class OC_Image {
imagedestroy($process);
return false;
}
+
+ // preserve transparency
+ if($this->imageType == IMAGETYPE_GIF or $this->imageType == IMAGETYPE_PNG) {
+ imagecolortransparent($process, imagecolorallocatealpha($process, 0, 0, 0, 127));
+ imagealphablending($process, false);
+ imagesavealpha($process, true);
+ }
+
imagecopyresampled($process, $this->resource, 0, 0, $x, $y, $w, $h, $w, $h);
if ($process == false) {
OC_Log::write('core', __METHOD__.'(): Error resampling process image '.$w.'x'.$h, OC_Log::ERROR);
diff --git a/lib/private/preview.php b/lib/private/preview.php
index 8089379bde5..6172519c7d1 100755
--- a/lib/private/preview.php
+++ b/lib/private/preview.php
@@ -561,9 +561,15 @@ class Preview {
$realX = (int)$image->width();
$realY = (int)$image->height();
- // compute $maxY using the aspect of the generated preview
+ // compute $maxY and $maxX using the aspect of the generated preview
if ($this->keepAspect) {
- $y = $x / ($realX / $realY);
+ $ratio = $realX / $realY;
+ if($x / $ratio < $y) {
+ // width restricted
+ $y = $x / $ratio;
+ } else {
+ $x = $y * $ratio;
+ }
}
if ($x === $realX && $y === $realY) {
diff --git a/lib/private/preview/mp3.php b/lib/private/preview/mp3.php
index 21f160fd50f..bb4d3dfce86 100644
--- a/lib/private/preview/mp3.php
+++ b/lib/private/preview/mp3.php
@@ -14,8 +14,6 @@ class MP3 extends Provider {
}
public function getThumbnail($path, $maxX, $maxY, $scalingup, $fileview) {
- require_once('getid3/getid3.php');
-
$getID3 = new \getID3();
$tmpPath = $fileview->toTmpFile($path);
diff --git a/lib/private/server.php b/lib/private/server.php
index da705863078..3299792e20d 100644
--- a/lib/private/server.php
+++ b/lib/private/server.php
@@ -255,7 +255,11 @@ class Server extends SimpleContainer implements IServerContainer {
* @return \OCP\Files\Folder
*/
function getUserFolder() {
- $dir = '/' . \OCP\User::getUser();
+ $user = $this->getUserSession()->getUser();
+ if (!$user) {
+ return null;
+ }
+ $dir = '/' . $user->getUID();
$root = $this->getRootFolder();
$folder = null;
diff --git a/lib/private/share/share.php b/lib/private/share/share.php
index 673c0dc383a..7fd5cd70e1d 100644
--- a/lib/private/share/share.php
+++ b/lib/private/share/share.php
@@ -595,6 +595,7 @@ class Share extends \OC\Share\Constants {
$shareWith['group'] = $group;
$shareWith['users'] = array_diff(\OC_Group::usersInGroup($group), array($uidOwner));
} else if ($shareType === self::SHARE_TYPE_LINK) {
+ $updateExistingShare = false;
if (\OC_Appconfig::getValue('core', 'shareapi_allow_links', 'yes') == 'yes') {
// when updating a link share
@@ -629,7 +630,7 @@ class Share extends \OC\Share\Constants {
throw new \Exception($message_t);
}
- if (!empty($updateExistingShare) &&
+ if ($updateExistingShare === false &&
self::isDefaultExpireDateEnabled() &&
empty($expirationDate)) {
$expirationDate = Helper::calcExpireDate();
@@ -925,19 +926,69 @@ class Share extends \OC\Share\Constants {
}
/**
+ * validate expire date if it meets all constraints
+ *
+ * @param string $expireDate well formate date string, e.g. "DD-MM-YYYY"
+ * @param string $shareTime timestamp when the file was shared
+ * @param string $itemType
+ * @param string $itemSource
+ * @return DateTime validated date
+ * @throws \Exception
+ */
+ private static function validateExpireDate($expireDate, $shareTime, $itemType, $itemSource) {
+ $l = \OC_L10N::get('lib');
+ $date = new \DateTime($expireDate);
+ $today = new \DateTime('now');
+
+ // if the user doesn't provide a share time we need to get it from the database
+ // fall-back mode to keep API stable, because the $shareTime parameter was added later
+ $defaultExpireDateEnforced = \OCP\Util::isDefaultExpireDateEnforced();
+ if ($defaultExpireDateEnforced && $shareTime === null) {
+ $items = self::getItemShared($itemType, $itemSource);
+ $firstItem = reset($items);
+ $shareTime = (int)$firstItem['stime'];
+ }
+
+ if ($defaultExpireDateEnforced) {
+ // initialize max date with share time
+ $maxDate = new \DateTime();
+ $maxDate->setTimestamp($shareTime);
+ $maxDays = \OCP\Config::getAppValue('core', 'shareapi_expire_after_n_days', '7');
+ $maxDate->add(new \DateInterval('P' . $maxDays . 'D'));
+ if ($date > $maxDate) {
+ $warning = 'Can not set expire date. Shares can not expire later then ' . $maxDays . ' after they where shared';
+ $warning_t = $l->t('Can not set expire date. Shares can not expire later then %s after they where shared', array($maxDays));
+ \OCP\Util::writeLog('OCP\Share', $warning, \OCP\Util::WARN);
+ throw new \Exception($warning_t);
+ }
+ }
+
+ if ($date < $today) {
+ $message = 'Can not set expire date. Expire date is in the past';
+ $message_t = $l->t('Can not set expire date. Expire date is in the past');
+ \OCP\Util::writeLog('OCP\Share', $message, \OCP\Util::WARN);
+ throw new \Exception($message_t);
+ }
+
+ return $date;
+ }
+
+ /**
* Set expiration date for a share
* @param string $itemType
* @param string $itemSource
* @param string $date expiration date
+ * @param int $shareTime timestamp from when the file was shared
+ * @throws \Exception
* @return boolean
*/
- public static function setExpirationDate($itemType, $itemSource, $date) {
+ public static function setExpirationDate($itemType, $itemSource, $date, $shareTime = null) {
$user = \OC_User::getUser();
if ($date == '') {
$date = null;
} else {
- $date = new \DateTime($date);
+ $date = self::validateExpireDate($date, $shareTime, $itemType, $itemSource);
}
$query = \OC_DB::prepare('UPDATE `*PREFIX*share` SET `expiration` = ? WHERE `item_type` = ? AND `item_source` = ? AND `uid_owner` = ? AND `share_type` = ?');
$query->bindValue(1, $date, 'datetime');
@@ -954,11 +1005,10 @@ class Share extends \OC\Share\Constants {
'date' => $date,
'uidOwner' => $user
));
-
+
return true;
+ }
- }
-
/**
* Checks whether a share has expired, calls unshareItem() if yes.
* @param array $item Share data (usually database row)
@@ -1348,7 +1398,7 @@ class Share extends \OC\Share\Constants {
}
}
// Check if resharing is allowed, if not remove share permission
- if (isset($row['permissions']) && !self::isResharingAllowed()) {
+ if (isset($row['permissions']) && (!self::isResharingAllowed() | \OC_Util::isSharingDisabledForUser())) {
$row['permissions'] &= ~\OCP\PERMISSION_SHARE;
}
// Add display names to result
diff --git a/lib/private/updater.php b/lib/private/updater.php
index d50c2554c75..7acd6446ec4 100644
--- a/lib/private/updater.php
+++ b/lib/private/updater.php
@@ -212,8 +212,6 @@ class Updater extends BasicEmitter {
\OC_DB::updateDbFromStructure(\OC::$SERVERROOT . '/db_structure.xml');
$this->emit('\OC\Updater', 'dbUpgrade');
- // TODO: why not do this at the end ?
- \OC_Config::setValue('version', implode('.', \OC_Util::getVersion()));
$disabledApps = \OC_App::checkAppsRequirements();
if (!empty($disabledApps)) {
$this->emit('\OC\Updater', 'disabledApps', array($disabledApps));
@@ -227,6 +225,9 @@ class Updater extends BasicEmitter {
//Invalidate update feed
\OC_Appconfig::setValue('core', 'lastupdatedat', 0);
+
+ // only set the final version if everything went well
+ \OC_Config::setValue('version', implode('.', \OC_Util::getVersion()));
}
}
}
diff --git a/lib/private/user/user.php b/lib/private/user/user.php
index f9c2cb4d130..993fb4c0c64 100644
--- a/lib/private/user/user.php
+++ b/lib/private/user/user.php
@@ -156,7 +156,7 @@ class User implements IUser {
* @param string $recoveryPassword for the encryption app to reset encryption keys
* @return bool
*/
- public function setPassword($password, $recoveryPassword) {
+ public function setPassword($password, $recoveryPassword = null) {
if ($this->emitter) {
$this->emitter->emit('\OC\User', 'preSetPassword', array($this, $password, $recoveryPassword));
}
diff --git a/lib/private/util.php b/lib/private/util.php
index eea194288f9..896b076afa6 100755
--- a/lib/private/util.php
+++ b/lib/private/util.php
@@ -22,7 +22,7 @@ class OC_Util {
self::$rootMounted = true;
}
}
-
+
/**
* mounting an object storage as the root fs will in essence remove the
* necessity of a data folder being present.
@@ -50,7 +50,7 @@ class OC_Util {
self::$rootMounted = true;
}
}
-
+
/**
* Can be set up
* @param string $user
@@ -171,6 +171,21 @@ class OC_Util {
}
/**
+ * check if share API enforces a default expire date
+ * @return boolean
+ */
+ public static function isDefaultExpireDateEnforced() {
+ $isDefaultExpireDateEnabled = \OCP\Config::getAppValue('core', 'shareapi_default_expire_date', 'no');
+ $enforceDefaultExpireDate = false;
+ if ($isDefaultExpireDateEnabled === 'yes') {
+ $value = \OCP\Config::getAppValue('core', 'shareapi_enforce_expire_date', 'no');
+ $enforceDefaultExpireDate = ($value === 'yes') ? true : false;
+ }
+
+ return $enforceDefaultExpireDate;
+ }
+
+ /**
* Get the quota of a user
* @param string $user
* @return int Quota bytes
@@ -1217,11 +1232,16 @@ class OC_Util {
/**
* @Brief Get file content via curl.
* @param string $url Url to get content
+ * @throws Exception If the URL does not start with http:// or https://
* @return string of the response or false on error
* This function get the content of a page via curl, if curl is enabled.
* If not, file_get_contents is used.
*/
public static function getUrlContent($url) {
+ if (strpos($url, 'http://') !== 0 && strpos($url, 'https://') !== 0) {
+ throw new Exception('$url must start with https:// or http://', 1);
+ }
+
if (function_exists('curl_init')) {
$curl = curl_init();
$max_redirects = 10;
diff --git a/lib/public/appframework/http/templateresponse.php b/lib/public/appframework/http/templateresponse.php
index 02589f4e2a4..c74d3b60254 100644
--- a/lib/public/appframework/http/templateresponse.php
+++ b/lib/public/appframework/http/templateresponse.php
@@ -134,8 +134,10 @@ class TemplateResponse extends Response {
* @return string the rendered html
*/
public function render(){
+ // \OCP\Template needs an empty string instead of 'blank' for an unwrapped response
+ $renderAs = $this->renderAs === 'blank' ? '' : $this->renderAs;
- $template = new \OCP\Template($this->appName, $this->templateName, $this->renderAs);
+ $template = new \OCP\Template($this->appName, $this->templateName, $renderAs);
foreach($this->params as $key => $value){
$template->assign($key, $value);
diff --git a/lib/public/iuser.php b/lib/public/iuser.php
index dc4acc7658f..c15edcd14dd 100644
--- a/lib/public/iuser.php
+++ b/lib/public/iuser.php
@@ -18,14 +18,14 @@ interface IUser {
public function getUID();
/**
- * get the displayname for the user, if no specific displayname is set it will fallback to the user id
+ * get the display name for the user, if no specific display name is set it will fallback to the user id
*
* @return string
*/
public function getDisplayName();
/**
- * set the displayname for the user
+ * set the display name for the user
*
* @param string $displayName
* @return bool
@@ -59,7 +59,7 @@ interface IUser {
* @param string $recoveryPassword for the encryption app to reset encryption keys
* @return bool
*/
- public function setPassword($password, $recoveryPassword);
+ public function setPassword($password, $recoveryPassword = null);
/**
* get the users home folder to mount
diff --git a/lib/public/share.php b/lib/public/share.php
index 8566a38c61e..c0939dce53f 100644
--- a/lib/public/share.php
+++ b/lib/public/share.php
@@ -298,10 +298,11 @@ class Share extends \OC\Share\Constants {
* @param string $itemType
* @param string $itemSource
* @param string $date expiration date
+ * @param int $shareTime timestamp from when the file was shared
* @return boolean
*/
- public static function setExpirationDate($itemType, $itemSource, $date) {
- return \OC\Share\Share::setExpirationDate($itemType, $itemSource, $date);
+ public static function setExpirationDate($itemType, $itemSource, $date, $shareTime = null) {
+ return \OC\Share\Share::setExpirationDate($itemType, $itemSource, $date, $shareTime);
}
/**
diff --git a/lib/public/util.php b/lib/public/util.php
index 8f4691eeade..2a6e977f085 100644
--- a/lib/public/util.php
+++ b/lib/public/util.php
@@ -518,6 +518,15 @@ class Util {
}
/**
+ * check if share API enforces a default expire date
+ * @return boolean
+ */
+ public static function isDefaultExpireDateEnforced() {
+ return \OC_Util::isDefaultExpireDateEnforced();
+ }
+
+
+ /**
* Checks whether the current version needs upgrade.
*
* @return bool true if upgrade is needed, false otherwise
diff --git a/settings/admin.php b/settings/admin.php
index 704f4519ff6..dd5f969fa1a 100755
--- a/settings/admin.php
+++ b/settings/admin.php
@@ -101,9 +101,11 @@ $tmpl->printPage();
* @return null|string
*/
function findBinaryPath($program) {
- exec('command -v ' . escapeshellarg($program) . ' 2> /dev/null', $output, $returnCode);
- if ($returnCode === 0 && count($output) > 0) {
- return escapeshellcmd($output[0]);
+ if (OC_Helper::is_function_enabled('exec')) {
+ exec('command -v ' . escapeshellarg($program) . ' 2> /dev/null', $output, $returnCode);
+ if ($returnCode === 0 && count($output) > 0) {
+ return escapeshellcmd($output[0]);
+ }
}
return null;
}
diff --git a/settings/js/apps.js b/settings/js/apps.js
index 3f9a9eab17a..9061b43c7be 100644
--- a/settings/js/apps.js
+++ b/settings/js/apps.js
@@ -398,7 +398,7 @@ $(document).ready(function(){
if(item) {
item.trigger('click');
item.addClass('active');
- $('#app-navigation').animate({scrollTop: $(item).offset().top-70}, 'slow','swing');
+ $('#app-navigation').animate({scrollTop: item.offset().top-70}, 'slow','swing');
}
}
diff --git a/tests/lib/contacts/localadressbook.php b/tests/lib/contacts/localadressbook.php
new file mode 100644
index 00000000000..bb69910820f
--- /dev/null
+++ b/tests/lib/contacts/localadressbook.php
@@ -0,0 +1,95 @@
+<?php
+use OC\Contacts\LocalAddressBook;
+
+/**
+ * ownCloud
+ *
+ * @author Thomas Müller
+ * @copyright 2014 Thomas Müller thomas.mueller@tmit.eu
+ *
+ * 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_LocalAddressBook extends PHPUnit_Framework_TestCase
+{
+
+ public function testSearchFN() {
+ $stub = $this->getMockForAbstractClass('\OCP\IUserManager', array('searchDisplayName'));
+
+ $stub->expects($this->any())->method('searchDisplayName')->will($this->returnValue(array(
+ new SimpleUserForTesting('tom', 'Thomas'),
+ new SimpleUserForTesting('tomtom', 'Thomas T.'),
+ )));
+
+ $localAddressBook = new LocalAddressBook($stub);
+
+ $result = $localAddressBook->search('tom', array('FN'), array());
+ $this->assertEquals(2, count($result));
+ }
+
+ public function testSearchId() {
+ $stub = $this->getMockForAbstractClass('\OCP\IUserManager', array('searchDisplayName'));
+
+ $stub->expects($this->any())->method('search')->will($this->returnValue(array(
+ new SimpleUserForTesting('tom', 'Thomas'),
+ new SimpleUserForTesting('tomtom', 'Thomas T.'),
+ )));
+
+ $localAddressBook = new LocalAddressBook($stub);
+
+ $result = $localAddressBook->search('tom', array('id'), array());
+ $this->assertEquals(2, count($result));
+ }
+}
+
+
+class SimpleUserForTesting implements \OCP\IUser {
+
+ public function __construct($uid, $displayName) {
+
+ $this->uid = $uid;
+ $this->displayName = $displayName;
+ }
+
+ public function getUID() {
+ return $this->uid;
+ }
+
+ public function getDisplayName() {
+ return $this->displayName;
+ }
+
+ public function setDisplayName($displayName) {
+ }
+
+ public function getLastLogin() {
+ }
+
+ public function updateLastLoginTimestamp() {
+ }
+
+ public function delete() {
+ }
+
+ public function setPassword($password, $recoveryPassword = null) {
+ }
+
+ public function getHome() {
+ }
+
+ public function canChangeAvatar() {
+ }
+
+ public function canChangePassword() {
+ }
+
+ public function canChangeDisplayName() {
+ }
+
+ public function isEnabled() {
+ }
+
+ public function setEnabled($enabled) {
+ }
+}
diff --git a/tests/lib/db/mysqlmigration.php b/tests/lib/db/mysqlmigration.php
new file mode 100644
index 00000000000..584df1d4465
--- /dev/null
+++ b/tests/lib/db/mysqlmigration.php
@@ -0,0 +1,39 @@
+<?php
+/**
+ * Copyright (c) 2014 Thomas Müller <deepdiver@owncloud.com>
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+
+class TestMySqlMigration extends \PHPUnit_Framework_TestCase {
+
+ /** @var \Doctrine\DBAL\Connection */
+ private $connection;
+
+ /** @var string */
+ private $tableName;
+
+ public function setUp() {
+ $this->connection = \OC_DB::getConnection();
+ if (!$this->connection->getDatabasePlatform() instanceof \Doctrine\DBAL\Platforms\MySqlPlatform) {
+ $this->markTestSkipped("Test only relevant on MySql");
+ }
+
+ $dbPrefix = \OC::$server->getConfig()->getSystemValue("dbtableprefix");
+ $this->tableName = uniqid($dbPrefix . "_enum_bit_test");
+ $this->connection->exec("CREATE TABLE $this->tableName(b BIT, e ENUM('1','2','3','4'))");
+ }
+
+ public function tearDown() {
+ $this->connection->getSchemaManager()->dropTable($this->tableName);
+ }
+
+ public function testNonOCTables() {
+ $manager = new \OC\DB\MDB2SchemaManager($this->connection);
+ $manager->updateDbFromStructure(__DIR__ . '/testschema.xml');
+
+ $this->assertTrue(true);
+ }
+
+}
diff --git a/tests/lib/db/sqlitemigration.php b/tests/lib/db/sqlitemigration.php
new file mode 100644
index 00000000000..adfc03a2ca7
--- /dev/null
+++ b/tests/lib/db/sqlitemigration.php
@@ -0,0 +1,39 @@
+<?php
+/**
+ * Copyright (c) 2014 Thomas Müller <deepdiver@owncloud.com>
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+
+class TestSqliteMigration extends \PHPUnit_Framework_TestCase {
+
+ /** @var \Doctrine\DBAL\Connection */
+ private $connection;
+
+ /** @var string */
+ private $tableName;
+
+ public function setUp() {
+ $this->connection = \OC_DB::getConnection();
+ if (!$this->connection->getDatabasePlatform() instanceof \Doctrine\DBAL\Platforms\SqlitePlatform) {
+ $this->markTestSkipped("Test only relevant on Sqlite");
+ }
+
+ $dbPrefix = \OC::$server->getConfig()->getSystemValue("dbtableprefix");
+ $this->tableName = uniqid($dbPrefix . "_enum_bit_test");
+ $this->connection->exec("CREATE TABLE $this->tableName(t0 tinyint unsigned, t1 tinyint)");
+ }
+
+ public function tearDown() {
+ $this->connection->getSchemaManager()->dropTable($this->tableName);
+ }
+
+ public function testNonOCTables() {
+ $manager = new \OC\DB\MDB2SchemaManager($this->connection);
+ $manager->updateDbFromStructure(__DIR__ . '/testschema.xml');
+
+ $this->assertTrue(true);
+ }
+
+}
diff --git a/tests/lib/share/share.php b/tests/lib/share/share.php
index 5920b44a8e0..bb827eece73 100644
--- a/tests/lib/share/share.php
+++ b/tests/lib/share/share.php
@@ -326,10 +326,14 @@ class Test_Share extends PHPUnit_Framework_TestCase {
$this->shareUserOneTestFileWithUserTwo();
$this->shareUserTestFileAsLink();
- $this->assertTrue(
- OCP\Share::setExpirationDate('test', 'test.txt', $this->dateInPast),
- 'Failed asserting that user 1 successfully set an expiration date for the test.txt share.'
- );
+ // manipulate share table and set expire date to the past
+ $query = \OC_DB::prepare('UPDATE `*PREFIX*share` SET `expiration` = ? WHERE `item_type` = ? AND `item_source` = ? AND `uid_owner` = ? AND `share_type` = ?');
+ $query->bindValue(1, new \DateTime($this->dateInPast), 'datetime');
+ $query->bindValue(2, 'test');
+ $query->bindValue(3, 'test.txt');
+ $query->bindValue(4, $this->user1);
+ $query->bindValue(5, \OCP\Share::SHARE_TYPE_LINK);
+ $query->execute();
$shares = OCP\Share::getItemsShared('test');
$this->assertSame(1, count($shares));
@@ -337,6 +341,24 @@ class Test_Share extends PHPUnit_Framework_TestCase {
$this->assertSame(\OCP\Share::SHARE_TYPE_USER, $share['share_type']);
}
+ public function testSetExpireDateInPast() {
+ OC_User::setUserId($this->user1);
+ $this->shareUserOneTestFileWithUserTwo();
+ $this->shareUserTestFileAsLink();
+
+ $setExpireDateFailed = false;
+ try {
+ $this->assertTrue(
+ OCP\Share::setExpirationDate('test', 'test.txt', $this->dateInPast, ''),
+ 'Failed asserting that user 1 successfully set an expiration date for the test.txt share.'
+ );
+ } catch (\Exception $e) {
+ $setExpireDateFailed = true;
+ }
+
+ $this->assertTrue($setExpireDateFailed);
+ }
+
public function testShareWithUserExpirationValid() {
OC_User::setUserId($this->user1);
$this->shareUserOneTestFileWithUserTwo();
@@ -344,7 +366,7 @@ class Test_Share extends PHPUnit_Framework_TestCase {
$this->assertTrue(
- OCP\Share::setExpirationDate('test', 'test.txt', $this->dateInFuture),
+ OCP\Share::setExpirationDate('test', 'test.txt', $this->dateInFuture, ''),
'Failed asserting that user 1 successfully set an expiration date for the test.txt share.'
);
@@ -353,6 +375,39 @@ class Test_Share extends PHPUnit_Framework_TestCase {
}
+ /*
+ * if user is in a group excluded from resharing, then the share permission should
+ * be removed
+ */
+ public function testShareWithUserAndUserIsExcludedFromResharing() {
+
+ OC_User::setUserId($this->user1);
+ $this->assertTrue(
+ OCP\Share::shareItem('test', 'test.txt', OCP\Share::SHARE_TYPE_USER, $this->user4, OCP\PERMISSION_ALL),
+ 'Failed asserting that user 1 successfully shared text.txt with user 4.'
+ );
+ $this->assertContains(
+ 'test.txt',
+ OCP\Share::getItemShared('test', 'test.txt', Test_Share_Backend::FORMAT_SOURCE),
+ 'Failed asserting that test.txt is a shared file of user 1.'
+ );
+
+ // exclude group2 from sharing
+ \OC_Appconfig::setValue('core', 'shareapi_exclude_groups_list', $this->group2);
+ \OC_Appconfig::setValue('core', 'shareapi_exclude_groups', "yes");
+
+ OC_User::setUserId($this->user4);
+
+ $share = OCP\Share::getItemSharedWith('test', 'test.txt');
+
+ $this->assertSame(\OCP\PERMISSION_ALL & ~OCP\PERMISSION_SHARE, $share['permissions'],
+ 'Failed asserting that user 4 is excluded from re-sharing');
+
+ \OC_Appconfig::deleteKey('core', 'shareapi_exclude_groups_list');
+ \OC_Appconfig::deleteKey('core', 'shareapi_exclude_groups');
+
+ }
+
protected function shareUserOneTestFileWithGroupOne() {
OC_User::setUserId($this->user1);
$this->assertTrue(
@@ -552,7 +607,7 @@ class Test_Share extends PHPUnit_Framework_TestCase {
// testGetShareByTokenExpirationValid
$this->assertTrue(
- OCP\Share::setExpirationDate('test', 'test.txt', $this->dateInFuture),
+ OCP\Share::setExpirationDate('test', 'test.txt', $this->dateInFuture, ''),
'Failed asserting that user 1 successfully set a future expiration date for the test.txt share.'
);
$row = $this->getShareByValidToken($token);
@@ -561,17 +616,47 @@ class Test_Share extends PHPUnit_Framework_TestCase {
'Failed asserting that the returned row has an expiration date.'
);
- // testGetShareByTokenExpirationExpired
- $this->assertTrue(
- OCP\Share::setExpirationDate('test', 'test.txt', $this->dateInPast),
- 'Failed asserting that user 1 successfully set a past expiration date for the test.txt share.'
- );
+ // manipulate share table and set expire date to the past
+ $query = \OC_DB::prepare('UPDATE `*PREFIX*share` SET `expiration` = ? WHERE `item_type` = ? AND `item_source` = ? AND `uid_owner` = ? AND `share_type` = ?');
+ $query->bindValue(1, new \DateTime($this->dateInPast), 'datetime');
+ $query->bindValue(2, 'test');
+ $query->bindValue(3, 'test.txt');
+ $query->bindValue(4, $this->user1);
+ $query->bindValue(5, \OCP\Share::SHARE_TYPE_LINK);
+ $query->execute();
+
$this->assertFalse(
OCP\Share::getShareByToken($token),
'Failed asserting that an expired share could not be found.'
);
}
+ public function testShareItemWithLinkAndDefaultExpireDate() {
+ OC_User::setUserId($this->user1);
+
+ \OC_Appconfig::setValue('core', 'shareapi_default_expire_date', 'yes');
+ \OC_Appconfig::setValue('core', 'shareapi_expire_after_n_days', '2');
+
+ $token = OCP\Share::shareItem('test', 'test.txt', OCP\Share::SHARE_TYPE_LINK, null, OCP\PERMISSION_READ);
+ $this->assertInternalType(
+ 'string',
+ $token,
+ 'Failed asserting that user 1 successfully shared text.txt as link with token.'
+ );
+
+ // share should have default expire date
+
+ $row = $this->getShareByValidToken($token);
+ $this->assertNotEmpty(
+ $row['expiration'],
+ 'Failed asserting that the returned row has an default expiration date.'
+ );
+
+ \OC_Appconfig::deleteKey('core', 'shareapi_default_expire_date');
+ \OC_Appconfig::deleteKey('core', 'shareapi_expire_after_n_days');
+
+ }
+
public function testUnshareAll() {
$this->shareUserTestFileWithUser($this->user1, $this->user2);
$this->shareUserTestFileWithUser($this->user2, $this->user3);