Merge branch 'master' into quota-space-root
1
.gitignore
vendored
|
@ -88,6 +88,7 @@ nbproject
|
|||
# Tests - auto-generated files
|
||||
/data-autotest
|
||||
/tests/coverage*
|
||||
/tests/karma-coverage
|
||||
/tests/autoconfig*
|
||||
/tests/autotest*
|
||||
/tests/data/lorem-copy.txt
|
||||
|
|
28
.jshintrc
Normal file
|
@ -0,0 +1,28 @@
|
|||
{
|
||||
"camelCase": true,
|
||||
"eqeqeq": true,
|
||||
"immed": true,
|
||||
"latedef": false,
|
||||
"noarg": true,
|
||||
"nonbsp": true,
|
||||
"undef": true,
|
||||
"unused": true,
|
||||
"trailing": true,
|
||||
"maxparams": 5,
|
||||
"curly": true,
|
||||
"jquery": true,
|
||||
"maxlen": 80,
|
||||
"indent": 4,
|
||||
"browser": true,
|
||||
"globals": {
|
||||
"console": true,
|
||||
"it": true,
|
||||
"itx": true,
|
||||
"expect": true,
|
||||
"describe": true,
|
||||
"beforeEach": true,
|
||||
"afterEach": true,
|
||||
"sinon": true,
|
||||
"fakeServer": true
|
||||
}
|
||||
}
|
|
@ -4,7 +4,9 @@
|
|||
A personal cloud which runs on your own server.
|
||||
|
||||
### Build Status on [Jenkins CI](https://ci.owncloud.org/)
|
||||
Git master: [![Build Status](https://ci.owncloud.org/buildStatus/icon?job=ownCloud-Server%28master%29)](https://ci.owncloud.org/job/ownCloud-Server%28master%29/)
|
||||
Git master: [![Build Status](https://ci.owncloud.org/job/server-master-linux/badge/icon)](https://ci.owncloud.org/job/server-master-linux/)
|
||||
|
||||
Quality: [![Scrutinizer Quality Score](https://scrutinizer-ci.com/g/owncloud/core/badges/quality-score.png?s=ce2f5ded03d4ac628e9ee5c767243fa7412e644f)](https://scrutinizer-ci.com/g/owncloud/core/)
|
||||
|
||||
### Installation instructions
|
||||
http://doc.owncloud.org/server/5.0/developer_manual/app/gettingstarted.html
|
||||
|
|
|
@ -64,6 +64,15 @@ if(strpos($filename, '/') !== false) {
|
|||
exit();
|
||||
}
|
||||
|
||||
if (!\OC\Files\Filesystem::file_exists($dir . '/')) {
|
||||
$result['data'] = array('message' => (string)$l10n->t(
|
||||
'The target folder has been moved or deleted.'),
|
||||
'code' => 'targetnotfound'
|
||||
);
|
||||
OCP\JSON::error($result);
|
||||
exit();
|
||||
}
|
||||
|
||||
//TODO why is stripslashes used on foldername in newfolder.php but not here?
|
||||
$target = $dir.'/'.$filename;
|
||||
|
||||
|
|
|
@ -29,6 +29,15 @@ if(strpos($foldername, '/') !== false) {
|
|||
exit();
|
||||
}
|
||||
|
||||
if (!\OC\Files\Filesystem::file_exists($dir . '/')) {
|
||||
$result['data'] = array('message' => (string)$l10n->t(
|
||||
'The target folder has been moved or deleted.'),
|
||||
'code' => 'targetnotfound'
|
||||
);
|
||||
OCP\JSON::error($result);
|
||||
exit();
|
||||
}
|
||||
|
||||
//TODO why is stripslashes used on foldername here but not in newfile.php?
|
||||
$target = $dir . '/' . stripslashes($foldername);
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ OCP\JSON::setContentTypeHeader('text/plain');
|
|||
// If no token is sent along, rely on login only
|
||||
|
||||
$allowedPermissions = OCP\PERMISSION_ALL;
|
||||
$errorCode = null;
|
||||
|
||||
$l = OC_L10N::get('files');
|
||||
if (empty($_POST['dirToken'])) {
|
||||
|
@ -125,7 +126,8 @@ if (strpos($dir, '..') === false) {
|
|||
|
||||
$meta = \OC\Files\Filesystem::getFileInfo($target);
|
||||
if ($meta === false) {
|
||||
$error = $l->t('Upload failed. Could not get file info.');
|
||||
$error = $l->t('The target folder has been moved or deleted.');
|
||||
$errorCode = 'targetnotfound';
|
||||
} else {
|
||||
$result[] = array('status' => 'success',
|
||||
'mime' => $meta['mimetype'],
|
||||
|
@ -177,5 +179,5 @@ if ($error === false) {
|
|||
OCP\JSON::encodedPrint($result);
|
||||
exit();
|
||||
} else {
|
||||
OCP\JSON::error(array(array('data' => array_merge(array('message' => $error), $storageStats))));
|
||||
OCP\JSON::error(array(array('data' => array_merge(array('message' => $error, 'code' => $errorCode), $storageStats))));
|
||||
}
|
||||
|
|
|
@ -52,6 +52,7 @@ $server->addPlugin(new OC_Connector_Sabre_FilesPlugin());
|
|||
$server->addPlugin(new OC_Connector_Sabre_AbortedUploadDetectionPlugin());
|
||||
$server->addPlugin(new OC_Connector_Sabre_QuotaPlugin());
|
||||
$server->addPlugin(new OC_Connector_Sabre_MaintenancePlugin());
|
||||
$server->addPlugin(new OC_Connector_Sabre_ExceptionLoggerPlugin('webdav'));
|
||||
|
||||
// And off we go!
|
||||
$server->exec();
|
||||
|
|
|
@ -65,10 +65,15 @@
|
|||
top: 44px;
|
||||
width: 100%;
|
||||
}
|
||||
#filestable tbody tr { background-color:#fff; height:40px; }
|
||||
#filestable, #controls {
|
||||
min-width: 680px;
|
||||
/* make sure there's enough room for the file actions */
|
||||
#body-user #filestable {
|
||||
min-width: 750px;
|
||||
}
|
||||
#body-user #controls {
|
||||
min-width: 600px;
|
||||
}
|
||||
|
||||
#filestable tbody tr { background-color:#fff; height:40px; }
|
||||
#filestable tbody tr:hover, tbody tr:active {
|
||||
background-color: rgb(240,240,240);
|
||||
}
|
||||
|
@ -98,7 +103,7 @@ table td {
|
|||
}
|
||||
table th#headerName {
|
||||
position: relative;
|
||||
width: 100em; /* not really sure why this works better than 100% … table styling */
|
||||
width: 9999px; /* not really sure why this works better than 100% … table styling */
|
||||
padding: 0;
|
||||
}
|
||||
#headerName-container {
|
||||
|
@ -114,7 +119,9 @@ table th#headerDate, table td.date {
|
|||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
position: relative;
|
||||
/* this can not be just width, both need to be set … table styling */
|
||||
min-width: 176px;
|
||||
max-width: 176px;
|
||||
}
|
||||
|
||||
/* Multiselect bar */
|
||||
|
@ -140,7 +147,7 @@ table.multiselect thead th {
|
|||
}
|
||||
table.multiselect #headerName {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
width: 9999px; /* when we use 100%, the styling breaks on mobile … table styling */
|
||||
}
|
||||
table td.selection, table th.selection, table td.fileaction { width:32px; text-align:center; }
|
||||
table td.filename a.name {
|
||||
|
@ -169,6 +176,15 @@ table td.filename .nametext, .uploadtext, .modified { float:left; padding:14px 0
|
|||
}
|
||||
.modified {
|
||||
position: relative;
|
||||
padding-left: 8px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
width: 90%;
|
||||
}
|
||||
/* ellipsize long modified dates to make room for showing delete button */
|
||||
#fileList tr:hover .modified,
|
||||
#fileList tr:focus .modified {
|
||||
width: 75%;
|
||||
}
|
||||
|
||||
/* TODO fix usability bug (accidental file/folder selection) */
|
||||
|
@ -242,7 +258,7 @@ table td.filename form { font-size:14px; margin-left:48px; margin-right:48px; }
|
|||
|
||||
#fileList tr td.filename a.name label {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
width: 80%;
|
||||
height: 50px;
|
||||
}
|
||||
|
||||
|
@ -253,6 +269,7 @@ table td.filename form { font-size:14px; margin-left:48px; margin-right:48px; }
|
|||
position: absolute;
|
||||
top: 14px;
|
||||
right: 0;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
#fileList img.move2trash { display:inline; margin:-8px 0; padding:16px 8px 16px 8px !important; float:right; }
|
||||
|
@ -261,6 +278,7 @@ table td.filename form { font-size:14px; margin-left:48px; margin-right:48px; }
|
|||
right: 0;
|
||||
padding: 28px 14px 19px !important;
|
||||
}
|
||||
|
||||
a.action>img { max-height:16px; max-width:16px; vertical-align:text-bottom; }
|
||||
|
||||
/* Actions for selected files */
|
||||
|
@ -290,6 +308,10 @@ a.action>img { max-height:16px; max-width:16px; vertical-align:text-bottom; }
|
|||
opacity: 0;
|
||||
display:none;
|
||||
}
|
||||
|
||||
#fileList a.action[data-action="Rename"] {
|
||||
padding:18px 14px !important;
|
||||
}
|
||||
#fileList tr:hover a.action, #fileList a.action.permanent {
|
||||
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=50)";
|
||||
filter: alpha(opacity=50);
|
||||
|
|
|
@ -63,7 +63,6 @@ $files = array();
|
|||
$user = OC_User::getUser();
|
||||
if (\OC\Files\Cache\Upgrade::needUpgrade($user)) { //dont load anything if we need to upgrade the cache
|
||||
$needUpgrade = true;
|
||||
$freeSpace = 0;
|
||||
} else {
|
||||
if ($isIE8){
|
||||
// after the redirect above, the URL will have a format
|
||||
|
@ -77,7 +76,6 @@ if (\OC\Files\Cache\Upgrade::needUpgrade($user)) { //dont load anything if we ne
|
|||
else{
|
||||
$files = \OCA\Files\Helper::getFiles($dir);
|
||||
}
|
||||
$freeSpace = \OC\Files\Filesystem::free_space($dir);
|
||||
$needUpgrade = false;
|
||||
}
|
||||
|
||||
|
@ -103,6 +101,8 @@ if ($needUpgrade) {
|
|||
} else {
|
||||
// information about storage capacities
|
||||
$storageInfo=OC_Helper::getStorageInfo($dir);
|
||||
$freeSpace=$storageInfo['free'];
|
||||
$uploadLimit=OCP\Util::uploadLimit();
|
||||
$maxUploadFilesize=OCP\Util::maxUploadFilesize($dir);
|
||||
$publicUploadEnabled = \OC_Appconfig::getValue('core', 'shareapi_allow_public_upload', 'yes');
|
||||
// if the encryption app is disabled, than everything is fine (INIT_SUCCESSFUL status code)
|
||||
|
@ -134,8 +134,10 @@ if ($needUpgrade) {
|
|||
$tmpl->assign('files', $files);
|
||||
$tmpl->assign('trash', $trashEnabled);
|
||||
$tmpl->assign('trashEmpty', $trashEmpty);
|
||||
$tmpl->assign('uploadMaxFilesize', $maxUploadFilesize);
|
||||
$tmpl->assign('uploadMaxFilesize', $maxUploadFilesize); // minimium of freeSpace and uploadLimit
|
||||
$tmpl->assign('uploadMaxHumanFilesize', OCP\Util::humanFileSize($maxUploadFilesize));
|
||||
$tmpl->assign('freeSpace', $freeSpace);
|
||||
$tmpl->assign('uploadLimit', $uploadLimit); // PHP upload limit
|
||||
$tmpl->assign('allowZipDownload', intval(OCP\Config::getSystemValue('allowZipDownload', true)));
|
||||
$tmpl->assign('usedSpacePercent', (int)$storageInfo['relative']);
|
||||
$tmpl->assign('isPublic', false);
|
||||
|
|
|
@ -1,3 +1,13 @@
|
|||
/*
|
||||
* Copyright (c) 2014
|
||||
*
|
||||
* This file is licensed under the Affero General Public License version 3
|
||||
* or later.
|
||||
*
|
||||
* See the COPYING-README file.
|
||||
*
|
||||
*/
|
||||
|
||||
function switchPublicFolder()
|
||||
{
|
||||
var publicEnable = $('#publicEnable').is(':checked');
|
||||
|
@ -10,7 +20,7 @@ function switchPublicFolder()
|
|||
$(document).ready(function(){
|
||||
switchPublicFolder(); // Execute the function after loading DOM tree
|
||||
$('#publicEnable').click(function(){
|
||||
switchPublicFolder(); // To get rid of onClick()
|
||||
switchPublicFolder(); // To get rid of onClick()
|
||||
});
|
||||
|
||||
$('#allowZipDownload').bind('change', function() {
|
||||
|
|
|
@ -1,3 +1,13 @@
|
|||
/*
|
||||
* Copyright (c) 2014
|
||||
*
|
||||
* This file is licensed under the Affero General Public License version 3
|
||||
* or later.
|
||||
*
|
||||
* See the COPYING-README file.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* The file upload code uses several hooks to interact with blueimps jQuery file upload library:
|
||||
* 1. the core upload handling hooks are added when initializing the plugin,
|
||||
|
@ -8,6 +18,8 @@
|
|||
* - TODO music upload button
|
||||
*/
|
||||
|
||||
/* global OC, t, n */
|
||||
|
||||
/**
|
||||
* Function that will allow us to know if Ajax uploads are supported
|
||||
* @link https://github.com/New-Bamboo/example-ajax-upload/blob/master/public/index.html
|
||||
|
@ -241,10 +253,22 @@ $(document).ready(function() {
|
|||
// add size
|
||||
selection.totalBytes += file.size;
|
||||
|
||||
//check max upload size
|
||||
if (selection.totalBytes > $('#max_upload').val()) {
|
||||
// check PHP upload limit
|
||||
if (selection.totalBytes > $('#upload_limit').val()) {
|
||||
data.textStatus = 'sizeexceedlimit';
|
||||
data.errorThrown = t('files', 'Total file size {size1} exceeds upload limit {size2}', {
|
||||
'size1': humanFileSize(selection.totalBytes),
|
||||
'size2': humanFileSize($('#upload_limit').val())
|
||||
});
|
||||
}
|
||||
|
||||
// check free space
|
||||
if (selection.totalBytes > $('#free_space').val()) {
|
||||
data.textStatus = 'notenoughspace';
|
||||
data.errorThrown = t('files', 'Not enough space available');
|
||||
data.errorThrown = t('files', 'Not enough free space, you are uploading {size1} but only {size2} is left', {
|
||||
'size1': humanFileSize(selection.totalBytes),
|
||||
'size2': humanFileSize($('#free_space').val())
|
||||
});
|
||||
}
|
||||
|
||||
// end upload for whole selection on error
|
||||
|
@ -315,6 +339,13 @@ $(document).ready(function() {
|
|||
} else {
|
||||
// HTTP connection problem
|
||||
OC.Notification.show(data.errorThrown);
|
||||
if (data.result) {
|
||||
var result = JSON.parse(data.result);
|
||||
if (result && result[0] && result[0].data && result[0].data.code === 'targetnotfound') {
|
||||
// abort upload of next files if any
|
||||
OC.Upload.cancelUploads();
|
||||
}
|
||||
}
|
||||
}
|
||||
//hide notification after 10 sec
|
||||
setTimeout(function() {
|
||||
|
|
|
@ -1,3 +1,15 @@
|
|||
/*
|
||||
* Copyright (c) 2014
|
||||
*
|
||||
* This file is licensed under the Affero General Public License version 3
|
||||
* or later.
|
||||
*
|
||||
* See the COPYING-README file.
|
||||
*
|
||||
*/
|
||||
|
||||
/* global OC, FileList */
|
||||
/* global trashBinApp */
|
||||
var FileActions = {
|
||||
actions: {},
|
||||
defaults: {},
|
||||
|
@ -45,8 +57,9 @@ var FileActions = {
|
|||
return filteredActions;
|
||||
},
|
||||
getDefault: function (mime, type, permissions) {
|
||||
var mimePart;
|
||||
if (mime) {
|
||||
var mimePart = mime.substr(0, mime.indexOf('/'));
|
||||
mimePart = mime.substr(0, mime.indexOf('/'));
|
||||
}
|
||||
var name = false;
|
||||
if (mime && FileActions.defaults[mime]) {
|
||||
|
@ -71,13 +84,15 @@ var FileActions = {
|
|||
FileActions.currentFile = parent;
|
||||
var actions = FileActions.get(FileActions.getCurrentMimeType(), FileActions.getCurrentType(), FileActions.getCurrentPermissions());
|
||||
var file = FileActions.getCurrentFile();
|
||||
var nameLinks;
|
||||
if (FileList.findFileEl(file).data('renaming')) {
|
||||
return;
|
||||
}
|
||||
|
||||
// recreate fileactions
|
||||
parent.children('a.name').find('.fileactions').remove();
|
||||
parent.children('a.name').append('<span class="fileactions" />');
|
||||
nameLinks = parent.children('a.name');
|
||||
nameLinks.find('.fileactions, .nametext .action').remove();
|
||||
nameLinks.append('<span class="fileactions" />');
|
||||
var defaultAction = FileActions.getDefault(FileActions.getCurrentMimeType(), FileActions.getCurrentType(), FileActions.getCurrentPermissions());
|
||||
|
||||
var actionHandler = function (event) {
|
||||
|
@ -97,21 +112,30 @@ var FileActions = {
|
|||
}
|
||||
|
||||
if ((name === 'Download' || action !== defaultAction) && name !== 'Delete') {
|
||||
var img = FileActions.icons[name];
|
||||
var img = FileActions.icons[name],
|
||||
actionText = t('files', name),
|
||||
actionContainer = 'a.name>span.fileactions';
|
||||
|
||||
if (name === 'Rename') {
|
||||
// rename has only an icon which appears behind
|
||||
// the file name
|
||||
actionText = '';
|
||||
actionContainer = 'a.name span.nametext';
|
||||
}
|
||||
if (img.call) {
|
||||
img = img(file);
|
||||
}
|
||||
var html = '<a href="#" class="action" data-action="' + name + '">';
|
||||
if (img) {
|
||||
html += '<img class ="svg" src="' + img + '" /> ';
|
||||
html += '<img class ="svg" src="' + img + '" />';
|
||||
}
|
||||
html += t('files', name) + '</a>';
|
||||
html += '<span> ' + actionText + '</span></a>';
|
||||
|
||||
var element = $(html);
|
||||
element.data('action', name);
|
||||
//alert(element);
|
||||
element.on('click', {a: null, elem: parent, actionFunc: actions[name]}, actionHandler);
|
||||
parent.find('a.name>span.fileactions').append(element);
|
||||
parent.find(actionContainer).append(element);
|
||||
}
|
||||
|
||||
};
|
||||
|
@ -130,13 +154,14 @@ var FileActions = {
|
|||
parent.parent().children().last().find('.action.delete').remove();
|
||||
if (actions['Delete']) {
|
||||
var img = FileActions.icons['Delete'];
|
||||
var html;
|
||||
if (img.call) {
|
||||
img = img(file);
|
||||
}
|
||||
if (typeof trashBinApp !== 'undefined' && trashBinApp) {
|
||||
var html = '<a href="#" original-title="' + t('files', 'Delete permanently') + '" class="action delete delete-icon" />';
|
||||
html = '<a href="#" original-title="' + t('files', 'Delete permanently') + '" class="action delete delete-icon" />';
|
||||
} else {
|
||||
var html = '<a href="#" class="action delete delete-icon" />';
|
||||
html = '<a href="#" class="action delete delete-icon" />';
|
||||
}
|
||||
var element = $(html);
|
||||
element.data('action', actions['Delete']);
|
||||
|
@ -163,17 +188,21 @@ var FileActions = {
|
|||
};
|
||||
|
||||
$(document).ready(function () {
|
||||
var downloadScope;
|
||||
if ($('#allowZipDownload').val() == 1) {
|
||||
var downloadScope = 'all';
|
||||
downloadScope = 'all';
|
||||
} else {
|
||||
var downloadScope = 'file';
|
||||
downloadScope = 'file';
|
||||
}
|
||||
|
||||
if (typeof disableDownloadActions == 'undefined' || !disableDownloadActions) {
|
||||
FileActions.register(downloadScope, 'Download', OC.PERMISSION_READ, function () {
|
||||
return OC.imagePath('core', 'actions/download');
|
||||
}, function (filename) {
|
||||
window.location = OC.filePath('files', 'ajax', 'download.php') + '?files=' + encodeURIComponent(filename) + '&dir=' + encodeURIComponent($('#dir').val());
|
||||
var url = FileList.getDownloadUrl(filename);
|
||||
if (url) {
|
||||
OC.redirect(url);
|
||||
}
|
||||
});
|
||||
}
|
||||
$('#fileList tr').each(function () {
|
||||
|
|
|
@ -1,4 +1,16 @@
|
|||
var FileList={
|
||||
/*
|
||||
* Copyright (c) 2014
|
||||
*
|
||||
* This file is licensed under the Affero General Public License version 3
|
||||
* or later.
|
||||
*
|
||||
* See the COPYING-README file.
|
||||
*
|
||||
*/
|
||||
|
||||
/* global OC, t, n, FileList, FileActions, Files */
|
||||
/* global procesSelection, dragOptions, SVGSupport, replaceSVG */
|
||||
window.FileList={
|
||||
useUndo:true,
|
||||
postProcessList: function() {
|
||||
$('#fileList tr').each(function() {
|
||||
|
@ -28,7 +40,8 @@ var FileList={
|
|||
}
|
||||
FileList.updateFileSummary();
|
||||
procesSelection();
|
||||
|
||||
|
||||
$(window).scrollTop(0);
|
||||
$fileList.trigger(jQuery.Event("updated"));
|
||||
},
|
||||
createRow:function(type, name, iconurl, linktarget, size, lastModified, permissions) {
|
||||
|
@ -191,6 +204,7 @@ var FileList={
|
|||
return OC.linkTo('files', 'index.php')+"?dir="+ encodeURIComponent(dir).replace(/%2F/g, '/');
|
||||
},
|
||||
setCurrentDir: function(targetDir, changeUrl) {
|
||||
var url;
|
||||
$('#dir').val(targetDir);
|
||||
if (changeUrl !== false) {
|
||||
if (window.history.pushState && changeUrl !== false) {
|
||||
|
@ -394,7 +408,7 @@ var FileList={
|
|||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
|
||||
form.submit(function(event) {
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
|
@ -468,7 +482,7 @@ var FileList={
|
|||
var basename = newname;
|
||||
if (newname.indexOf('.') > 0 && tr.data('type') !== 'dir') {
|
||||
basename = newname.substr(0, newname.lastIndexOf('.'));
|
||||
}
|
||||
}
|
||||
td.find('a.name span.nametext').text(basename);
|
||||
if (newname.indexOf('.') > 0 && tr.data('type') !== 'dir') {
|
||||
if ( ! td.find('a.name span.extension').exists() ) {
|
||||
|
@ -477,6 +491,7 @@ var FileList={
|
|||
td.find('a.name span.extension').text(newname.substr(newname.lastIndexOf('.')));
|
||||
}
|
||||
form.remove();
|
||||
FileActions.display( tr.find('td.filename'), true);
|
||||
td.children('a.name').show();
|
||||
} catch (error) {
|
||||
input.attr('title', error);
|
||||
|
@ -780,6 +795,20 @@ var FileList={
|
|||
$('#fileList tr.searchresult').each(function(i,e) {
|
||||
$(e).removeClass("searchresult");
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the download URL of the given file
|
||||
* @param filename file name of the file
|
||||
* @param dir optional directory in which the file name is, defaults to the current directory
|
||||
*/
|
||||
getDownloadUrl: function(filename, dir) {
|
||||
var params = {
|
||||
files: filename,
|
||||
dir: dir || FileList.getCurrentDirectory(),
|
||||
download: null
|
||||
};
|
||||
return OC.filePath('files', 'ajax', 'download.php') + '?' + OC.buildQueryString(params);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -819,7 +848,7 @@ $(document).ready(function() {
|
|||
{name: 'requesttoken', value: oc_requesttoken}
|
||||
];
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
file_upload_start.on('fileuploadadd', function(e, data) {
|
||||
|
@ -858,7 +887,7 @@ $(document).ready(function() {
|
|||
*/
|
||||
file_upload_start.on('fileuploaddone', function(e, data) {
|
||||
OC.Upload.log('filelist handle fileuploaddone', e, data);
|
||||
|
||||
|
||||
var response;
|
||||
if (typeof data.result === 'string') {
|
||||
response = data.result;
|
||||
|
|
|
@ -1,4 +1,16 @@
|
|||
Files={
|
||||
/*
|
||||
* Copyright (c) 2014
|
||||
*
|
||||
* This file is licensed under the Affero General Public License version 3
|
||||
* or later.
|
||||
*
|
||||
* See the COPYING-README file.
|
||||
*
|
||||
*/
|
||||
|
||||
/* global OC, t, n, FileList, FileActions */
|
||||
/* global getURLParameter, isPublic */
|
||||
var Files = {
|
||||
// file space size sync
|
||||
_updateStorageStatistics: function() {
|
||||
Files._updateStorageStatisticsTimeout = null;
|
||||
|
@ -41,6 +53,7 @@ Files={
|
|||
}
|
||||
if (response.data !== undefined && response.data.uploadMaxFilesize !== undefined) {
|
||||
$('#max_upload').val(response.data.uploadMaxFilesize);
|
||||
$('#free_space').val(response.data.freeSpace);
|
||||
$('#upload.button').attr('original-title', response.data.maxHumanFilesize);
|
||||
$('#usedSpacePercent').val(response.data.usedSpacePercent);
|
||||
Files.displayStorageWarnings();
|
||||
|
@ -67,17 +80,25 @@ Files={
|
|||
return fileName;
|
||||
},
|
||||
|
||||
isFileNameValid:function (name) {
|
||||
if (name === '.') {
|
||||
throw t('files', '\'.\' is an invalid file name.');
|
||||
} else if (name.length === 0) {
|
||||
/**
|
||||
* Checks whether the given file name is valid.
|
||||
* @param name file name to check
|
||||
* @return true if the file name is valid.
|
||||
* Throws a string exception with an error message if
|
||||
* the file name is not valid
|
||||
*/
|
||||
isFileNameValid: function (name) {
|
||||
var trimmedName = name.trim();
|
||||
if (trimmedName === '.' || trimmedName === '..') {
|
||||
throw t('files', '"{name}" is an invalid file name.', {name: name});
|
||||
} else if (trimmedName.length === 0) {
|
||||
throw t('files', 'File name cannot be empty.');
|
||||
}
|
||||
|
||||
// check for invalid characters
|
||||
var invalid_characters = ['\\', '/', '<', '>', ':', '"', '|', '?', '*'];
|
||||
var invalid_characters =
|
||||
['\\', '/', '<', '>', ':', '"', '|', '?', '*', '\n'];
|
||||
for (var i = 0; i < invalid_characters.length; i++) {
|
||||
if (name.indexOf(invalid_characters[i]) !== -1) {
|
||||
if (trimmedName.indexOf(invalid_characters[i]) !== -1) {
|
||||
throw t('files', "Invalid name, '\\', '/', '<', '>', ':', '\"', '|', '?' and '*' are not allowed.");
|
||||
}
|
||||
}
|
||||
|
@ -654,10 +675,10 @@ function procesSelection() {
|
|||
var totalSize = 0;
|
||||
for(var i=0; i<selectedFiles.length; i++) {
|
||||
totalSize+=selectedFiles[i].size;
|
||||
};
|
||||
}
|
||||
for(var i=0; i<selectedFolders.length; i++) {
|
||||
totalSize+=selectedFolders[i].size;
|
||||
};
|
||||
}
|
||||
$('#headerSize').text(humanFileSize(totalSize));
|
||||
var selection = '';
|
||||
if (selectedFolders.length > 0) {
|
||||
|
@ -751,7 +772,7 @@ Files.lazyLoadPreview = function(path, mime, ready, width, height, etag) {
|
|||
console.warn('Files.lazyLoadPreview(): missing etag argument');
|
||||
}
|
||||
|
||||
if ( $('#public_upload').length ) {
|
||||
if ( $('#isPublic').length ) {
|
||||
urlSpec.t = $('#dirToken').val();
|
||||
previewURL = OC.Router.generate('core_ajax_public_preview', urlSpec);
|
||||
} else {
|
||||
|
@ -769,10 +790,11 @@ Files.lazyLoadPreview = function(path, mime, ready, width, height, etag) {
|
|||
}
|
||||
img.src = previewURL;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
function getUniqueName(name) {
|
||||
if (FileList.findFileEl(name).exists()) {
|
||||
var numMatch;
|
||||
var parts=name.split('.');
|
||||
var extension = "";
|
||||
if (parts.length > 1) {
|
||||
|
@ -806,7 +828,7 @@ function checkTrashStatus() {
|
|||
|
||||
function onClickBreadcrumb(e) {
|
||||
var $el = $(e.target).closest('.crumb'),
|
||||
$targetDir = $el.data('dir');
|
||||
$targetDir = $el.data('dir'),
|
||||
isPublic = !!$('#isPublic').val();
|
||||
|
||||
if ($targetDir !== undefined && !isPublic) {
|
||||
|
|
|
@ -1,3 +1,14 @@
|
|||
/*
|
||||
* Copyright (c) 2014
|
||||
*
|
||||
* This file is licensed under the Affero General Public License version 3
|
||||
* or later.
|
||||
*
|
||||
* See the COPYING-README file.
|
||||
*
|
||||
*/
|
||||
|
||||
/* global OC */
|
||||
$(document).ready(function () {
|
||||
var eventSource, total, bar = $('#progressbar');
|
||||
console.log('start');
|
||||
|
|
|
@ -1,3 +1,14 @@
|
|||
/*
|
||||
* Copyright (c) 2014
|
||||
*
|
||||
* This file is licensed under the Affero General Public License version 3
|
||||
* or later.
|
||||
*
|
||||
* See the COPYING-README file.
|
||||
*
|
||||
*/
|
||||
|
||||
/* global OC */
|
||||
function Upload(fileSelector) {
|
||||
if ($.support.xhrFileUpload) {
|
||||
return new XHRUpload(fileSelector.target.files);
|
||||
|
|
|
@ -59,6 +59,13 @@ class App {
|
|||
$result['data'] = array(
|
||||
'message' => $this->l10n->t("Invalid folder name. Usage of 'Shared' is reserved.")
|
||||
);
|
||||
// rename to non-existing folder is denied
|
||||
} else if (!$this->view->file_exists($dir)) {
|
||||
$result['data'] = array('message' => (string)$this->l10n->t(
|
||||
'The target folder has been moved or deleted.',
|
||||
array($dir)),
|
||||
'code' => 'targetnotfound'
|
||||
);
|
||||
// rename to existing file is denied
|
||||
} else if ($this->view->file_exists($dir . '/' . $newname)) {
|
||||
|
||||
|
@ -83,14 +90,17 @@ class App {
|
|||
else {
|
||||
$meta['type'] = 'file';
|
||||
}
|
||||
// these need to be set for determineIcon()
|
||||
$meta['isPreviewAvailable'] = \OC::$server->getPreviewManager()->isMimeSupported($meta['mimetype']);
|
||||
$meta['directory'] = $dir;
|
||||
$fileinfo = array(
|
||||
'id' => $meta['fileid'],
|
||||
'mime' => $meta['mimetype'],
|
||||
'size' => $meta['size'],
|
||||
'etag' => $meta['etag'],
|
||||
'directory' => $dir,
|
||||
'directory' => $meta['directory'],
|
||||
'name' => $newname,
|
||||
'isPreviewAvailable' => \OC::$server->getPreviewManager()->isMimeSupported($meta['mimetype']),
|
||||
'isPreviewAvailable' => $meta['isPreviewAvailable'],
|
||||
'icon' => \OCA\Files\Helper::determineIcon($meta)
|
||||
);
|
||||
$result['success'] = true;
|
||||
|
|
|
@ -15,6 +15,7 @@ class Helper
|
|||
|
||||
return array('uploadMaxFilesize' => $maxUploadFilesize,
|
||||
'maxHumanFilesize' => $maxHumanFilesize,
|
||||
'freeSpace' => $storageInfo['free'],
|
||||
'usedSpacePercent' => (int)$storageInfo['relative']);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
<div id="controls">
|
||||
<?php print_unescaped($_['breadcrumb']); ?>
|
||||
<div class="actions creatable <?php if (!$_['isCreatable']):?>hidden<?php endif; ?>">
|
||||
<?php if(!isset($_['dirToken'])):?>
|
||||
<div id="new" class="button">
|
||||
<a><?php p($l->t('New'));?></a>
|
||||
<ul>
|
||||
|
@ -12,11 +13,17 @@
|
|||
data-type='web'><p><?php p($l->t('From link'));?></p></li>
|
||||
</ul>
|
||||
</div>
|
||||
<?php endif;?>
|
||||
<div id="upload" class="button"
|
||||
title="<?php p($l->t('Upload') . ' max. '.$_['uploadMaxHumanFilesize']) ?>">
|
||||
<?php if($_['uploadMaxFilesize'] >= 0):?>
|
||||
<input type="hidden" name="MAX_FILE_SIZE" id="max_upload"
|
||||
value="<?php p($_['uploadMaxFilesize']) ?>">
|
||||
<input type="hidden" id="max_upload" name="MAX_FILE_SIZE" value="<?php p($_['uploadMaxFilesize']) ?>">
|
||||
<?php endif;?>
|
||||
<input type="hidden" id="upload_limit" value="<?php p($_['uploadLimit']) ?>">
|
||||
<input type="hidden" id="free_space" value="<?php p($_['freeSpace']) ?>">
|
||||
<?php if(isset($_['dirToken'])):?>
|
||||
<input type="hidden" id="publicUploadRequestToken" name="requesttoken" value="<?php p($_['requesttoken']) ?>" />
|
||||
<input type="hidden" id="dirToken" name="dirToken" value="<?php p($_['dirToken']) ?>" />
|
||||
<?php endif;?>
|
||||
<input type="hidden" class="max_human_file_size"
|
||||
value="(max <?php p($_['uploadMaxHumanFilesize']); ?>)">
|
||||
|
@ -26,7 +33,7 @@
|
|||
<a href="#" class="svg icon icon-upload"></a>
|
||||
</div>
|
||||
<?php if ($_['trash']): ?>
|
||||
<input id="trash" type="button" value="<?php p($l->t('Deleted files'));?>" class="button" <?php $_['trashEmpty'] ? p('disabled') : '' ?>></input>
|
||||
<input id="trash" type="button" value="<?php p($l->t('Deleted files'));?>" class="button" <?php $_['trashEmpty'] ? p('disabled') : '' ?> />
|
||||
<?php endif; ?>
|
||||
<div id="uploadprogresswrapper">
|
||||
<div id="uploadprogressbar"></div>
|
||||
|
@ -44,7 +51,7 @@
|
|||
|
||||
<div id="emptycontent" <?php if (!$_['emptyContent']):?>class="hidden"<?php endif; ?>><?php p($l->t('Nothing in here. Upload something!'))?></div>
|
||||
|
||||
<input type="hidden" id="disableSharing" data-status="<?php p($_['disableSharing']); ?>"></input>
|
||||
<input type="hidden" id="disableSharing" data-status="<?php p($_['disableSharing']); ?>" />
|
||||
|
||||
<table id="filestable" data-allow-public-upload="<?php p($_['publicUploadEnabled'])?>" data-preview-x="36" data-preview-y="36">
|
||||
<thead>
|
||||
|
|
|
@ -38,7 +38,7 @@ class Test_OC_Files_App_Rename extends \PHPUnit_Framework_TestCase {
|
|||
$l10nMock->expects($this->any())
|
||||
->method('t')
|
||||
->will($this->returnArgument(0));
|
||||
$viewMock = $this->getMock('\OC\Files\View', array('rename', 'normalizePath', 'getFileInfo'), array(), '', false);
|
||||
$viewMock = $this->getMock('\OC\Files\View', array('rename', 'normalizePath', 'getFileInfo', 'file_exists'), array(), '', false);
|
||||
$viewMock->expects($this->any())
|
||||
->method('normalizePath')
|
||||
->will($this->returnArgument(0));
|
||||
|
@ -63,6 +63,11 @@ class Test_OC_Files_App_Rename extends \PHPUnit_Framework_TestCase {
|
|||
$oldname = 'Shared';
|
||||
$newname = 'new_name';
|
||||
|
||||
$this->viewMock->expects($this->at(0))
|
||||
->method('file_exists')
|
||||
->with('/')
|
||||
->will($this->returnValue(true));
|
||||
|
||||
$result = $this->files->rename($dir, $oldname, $newname);
|
||||
$expected = array(
|
||||
'success' => false,
|
||||
|
@ -80,6 +85,11 @@ class Test_OC_Files_App_Rename extends \PHPUnit_Framework_TestCase {
|
|||
$oldname = 'Shared';
|
||||
$newname = 'new_name';
|
||||
|
||||
$this->viewMock->expects($this->at(0))
|
||||
->method('file_exists')
|
||||
->with('/test')
|
||||
->will($this->returnValue(true));
|
||||
|
||||
$this->viewMock->expects($this->any())
|
||||
->method('getFileInfo')
|
||||
->will($this->returnValue(array(
|
||||
|
@ -129,6 +139,11 @@ class Test_OC_Files_App_Rename extends \PHPUnit_Framework_TestCase {
|
|||
$oldname = 'oldname';
|
||||
$newname = 'newname';
|
||||
|
||||
$this->viewMock->expects($this->at(0))
|
||||
->method('file_exists')
|
||||
->with('/')
|
||||
->will($this->returnValue(true));
|
||||
|
||||
$this->viewMock->expects($this->any())
|
||||
->method('getFileInfo')
|
||||
->will($this->returnValue(array(
|
||||
|
@ -141,7 +156,6 @@ class Test_OC_Files_App_Rename extends \PHPUnit_Framework_TestCase {
|
|||
'name' => 'new_name',
|
||||
)));
|
||||
|
||||
|
||||
$result = $this->files->rename($dir, $oldname, $newname);
|
||||
|
||||
$this->assertTrue($result['success']);
|
||||
|
@ -154,4 +168,35 @@ class Test_OC_Files_App_Rename extends \PHPUnit_Framework_TestCase {
|
|||
$this->assertEquals(\OC_Helper::mimetypeIcon('dir'), $result['data']['icon']);
|
||||
$this->assertFalse($result['data']['isPreviewAvailable']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test rename inside a folder that doesn't exist any more
|
||||
*/
|
||||
function testRenameInNonExistingFolder() {
|
||||
$dir = '/unexist';
|
||||
$oldname = 'oldname';
|
||||
$newname = 'newname';
|
||||
|
||||
$this->viewMock->expects($this->at(0))
|
||||
->method('file_exists')
|
||||
->with('/unexist')
|
||||
->will($this->returnValue(false));
|
||||
|
||||
$this->viewMock->expects($this->any())
|
||||
->method('getFileInfo')
|
||||
->will($this->returnValue(array(
|
||||
'fileid' => 123,
|
||||
'type' => 'dir',
|
||||
'mimetype' => 'httpd/unix-directory',
|
||||
'size' => 18,
|
||||
'etag' => 'abcdef',
|
||||
'directory' => '/unexist',
|
||||
'name' => 'new_name',
|
||||
)));
|
||||
|
||||
$result = $this->files->rename($dir, $oldname, $newname);
|
||||
|
||||
$this->assertFalse($result['success']);
|
||||
$this->assertEquals('targetnotfound', $result['data']['code']);
|
||||
}
|
||||
}
|
||||
|
|
75
apps/files/tests/js/fileactionsSpec.js
Normal file
|
@ -0,0 +1,75 @@
|
|||
/**
|
||||
* ownCloud
|
||||
*
|
||||
* @author Vincent Petry
|
||||
* @copyright 2014 Vincent Petry <pvince81@owncloud.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/* global OC, FileActions, FileList */
|
||||
describe('FileActions tests', function() {
|
||||
var $filesTable;
|
||||
beforeEach(function() {
|
||||
// init horrible parameters
|
||||
var $body = $('body');
|
||||
$body.append('<input type="hidden" id="dir" value="/subdir"></input>');
|
||||
$body.append('<input type="hidden" id="permissions" value="31"></input>');
|
||||
// dummy files table
|
||||
$filesTable = $body.append('<table id="filestable"></table>');
|
||||
});
|
||||
afterEach(function() {
|
||||
$('#dir, #permissions, #filestable').remove();
|
||||
});
|
||||
it('calling display() sets file actions', function() {
|
||||
// note: download_url is actually the link target, not the actual download URL...
|
||||
var $tr = FileList.addFile('testName.txt', 1234, new Date(), false, false, {download_url: 'test/download/url'});
|
||||
|
||||
// no actions before call
|
||||
expect($tr.find('.action[data-action=Download]').length).toEqual(0);
|
||||
expect($tr.find('.action[data-action=Rename]').length).toEqual(0);
|
||||
expect($tr.find('.action.delete').length).toEqual(0);
|
||||
|
||||
FileActions.display($tr.find('td.filename'), true);
|
||||
|
||||
// actions defined after cal
|
||||
expect($tr.find('.action[data-action=Download]').length).toEqual(1);
|
||||
expect($tr.find('.nametext .action[data-action=Rename]').length).toEqual(1);
|
||||
expect($tr.find('.action.delete').length).toEqual(1);
|
||||
});
|
||||
it('calling display() twice correctly replaces file actions', function() {
|
||||
var $tr = FileList.addFile('testName.txt', 1234, new Date(), false, false, {download_url: 'test/download/url'});
|
||||
|
||||
FileActions.display($tr.find('td.filename'), true);
|
||||
FileActions.display($tr.find('td.filename'), true);
|
||||
|
||||
// actions defined after cal
|
||||
expect($tr.find('.action[data-action=Download]').length).toEqual(1);
|
||||
expect($tr.find('.nametext .action[data-action=Rename]').length).toEqual(1);
|
||||
expect($tr.find('.action.delete').length).toEqual(1);
|
||||
});
|
||||
it('redirects to download URL when clicking download', function() {
|
||||
var redirectStub = sinon.stub(OC, 'redirect');
|
||||
// note: download_url is actually the link target, not the actual download URL...
|
||||
var $tr = FileList.addFile('test download File.txt', 1234, new Date(), false, false, {download_url: 'test/download/url'});
|
||||
FileActions.display($tr.find('td.filename'), true);
|
||||
|
||||
$tr.find('.action[data-action=Download]').click();
|
||||
|
||||
expect(redirectStub.calledOnce).toEqual(true);
|
||||
expect(redirectStub.getCall(0).args[0]).toEqual(OC.webroot + '/index.php/apps/files/ajax/download.php?files=test%20download%20File.txt&dir=%2Fsubdir&download');
|
||||
redirectStub.restore();
|
||||
});
|
||||
});
|
|
@ -18,25 +18,32 @@
|
|||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/* global OC, FileList */
|
||||
describe('FileList tests', function() {
|
||||
beforeEach(function() {
|
||||
// init horrible parameters
|
||||
$('<input type="hidden" id="dir" value="/subdir"></input>').append('body');
|
||||
$('<input type="hidden" id="permissions" value="31"></input>').append('body');
|
||||
var $body = $('body');
|
||||
$body.append('<input type="hidden" id="dir" value="/subdir"></input>');
|
||||
$body.append('<input type="hidden" id="permissions" value="31"></input>');
|
||||
// dummy files table
|
||||
$body.append('<table id="filestable"></table>');
|
||||
});
|
||||
afterEach(function() {
|
||||
$('#dir, #permissions').remove();
|
||||
$('#dir, #permissions, #filestable').remove();
|
||||
});
|
||||
it('generates file element with correct attributes when calling addFile', function() {
|
||||
var lastMod = new Date(10000);
|
||||
// note: download_url is actually the link target, not the actual download URL...
|
||||
var $tr = FileList.addFile('testName.txt', 1234, lastMod, false, false, {download_url: 'test/download/url'});
|
||||
|
||||
expect($tr).toBeDefined();
|
||||
expect($tr[0].tagName.toLowerCase()).toEqual('tr');
|
||||
expect($tr.find('a:first').attr('href')).toEqual('test/download/url');
|
||||
expect($tr.attr('data-type')).toEqual('file');
|
||||
expect($tr.attr('data-file')).toEqual('testName.txt');
|
||||
expect($tr.attr('data-size')).toEqual('1234');
|
||||
//expect($tr.attr('data-permissions')).toEqual('31');
|
||||
expect($tr.attr('data-permissions')).toEqual('31');
|
||||
//expect($tr.attr('data-mime')).toEqual('plain/text');
|
||||
});
|
||||
it('generates dir element with correct attributes when calling addDir', function() {
|
||||
|
@ -48,7 +55,11 @@ describe('FileList tests', function() {
|
|||
expect($tr.attr('data-type')).toEqual('dir');
|
||||
expect($tr.attr('data-file')).toEqual('testFolder');
|
||||
expect($tr.attr('data-size')).toEqual('1234');
|
||||
//expect($tr.attr('data-permissions')).toEqual('31');
|
||||
expect($tr.attr('data-permissions')).toEqual('31');
|
||||
//expect($tr.attr('data-mime')).toEqual('httpd/unix-directory');
|
||||
});
|
||||
it('returns correct download URL', function() {
|
||||
expect(FileList.getDownloadUrl('some file.txt')).toEqual(OC.webroot + '/index.php/apps/files/ajax/download.php?files=some%20file.txt&dir=%2Fsubdir&download');
|
||||
expect(FileList.getDownloadUrl('some file.txt', '/anotherpath/abc')).toEqual(OC.webroot + '/index.php/apps/files/ajax/download.php?files=some%20file.txt&dir=%2Fanotherpath%2Fabc&download');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/* global Files */
|
||||
describe('Files tests', function() {
|
||||
describe('File name validation', function() {
|
||||
it('Validates correct file names', function() {
|
||||
|
@ -36,12 +38,14 @@ describe('Files tests', function() {
|
|||
'und Ümläüte sind auch willkommen'
|
||||
];
|
||||
for ( var i = 0; i < fileNames.length; i++ ) {
|
||||
var error = false;
|
||||
try {
|
||||
expect(Files.isFileNameValid(fileNames[i])).toEqual(true);
|
||||
}
|
||||
catch (e) {
|
||||
fail();
|
||||
error = e;
|
||||
}
|
||||
expect(error).toEqual(false);
|
||||
}
|
||||
});
|
||||
it('Detects invalid file names', function() {
|
||||
|
@ -69,7 +73,7 @@ describe('Files tests', function() {
|
|||
var threwException = false;
|
||||
try {
|
||||
Files.isFileNameValid(fileNames[i]);
|
||||
fail();
|
||||
console.error('Invalid file name not detected:', fileNames[i]);
|
||||
}
|
||||
catch (e) {
|
||||
threwException = true;
|
||||
|
|
|
@ -32,6 +32,8 @@ class Hooks {
|
|||
|
||||
// file for which we want to rename the keys after the rename operation was successful
|
||||
private static $renamedFiles = array();
|
||||
// file for which we want to delete the keys after the delete operation was successful
|
||||
private static $deleteFiles = array();
|
||||
|
||||
/**
|
||||
* @brief Startup encryption backend upon user login
|
||||
|
@ -630,4 +632,66 @@ class Hooks {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief if the file was really deleted we remove the encryption keys
|
||||
* @param array $params
|
||||
* @return boolean
|
||||
*/
|
||||
public static function postDelete($params) {
|
||||
|
||||
if (!isset(self::$deleteFiles[$params[\OC\Files\Filesystem::signal_param_path]])) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$deletedFile = self::$deleteFiles[$params[\OC\Files\Filesystem::signal_param_path]];
|
||||
$path = $deletedFile['path'];
|
||||
$user = $deletedFile['uid'];
|
||||
|
||||
// we don't need to remember the file any longer
|
||||
unset(self::$deleteFiles[$params[\OC\Files\Filesystem::signal_param_path]]);
|
||||
|
||||
$view = new \OC\Files\View('/');
|
||||
|
||||
// return if the file still exists and wasn't deleted correctly
|
||||
if ($view->file_exists('/' . $user . '/files/' . $path)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Disable encryption proxy to prevent recursive calls
|
||||
$proxyStatus = \OC_FileProxy::$enabled;
|
||||
\OC_FileProxy::$enabled = false;
|
||||
|
||||
// Delete keyfile & shareKey so it isn't orphaned
|
||||
if (!Keymanager::deleteFileKey($view, $path, $user)) {
|
||||
\OCP\Util::writeLog('Encryption library',
|
||||
'Keyfile or shareKey could not be deleted for file "' . $user.'/files/'.$path . '"', \OCP\Util::ERROR);
|
||||
}
|
||||
|
||||
Keymanager::delAllShareKeys($view, $user, $path);
|
||||
|
||||
\OC_FileProxy::$enabled = $proxyStatus;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief remember the file which should be deleted and it's owner
|
||||
* @param array $params
|
||||
* @return boolean
|
||||
*/
|
||||
public static function preDelete($params) {
|
||||
$path = $params[\OC\Files\Filesystem::signal_param_path];
|
||||
|
||||
// skip this method if the trash bin is enabled or if we delete a file
|
||||
// outside of /data/user/files
|
||||
if (\OCP\App::isEnabled('files_trashbin')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$util = new Util(new \OC_FilesystemView('/'), \OCP\USER::getUser());
|
||||
list($owner, $ownerPath) = $util->getUidAndFilename($path);
|
||||
|
||||
self::$deleteFiles[$params[\OC\Files\Filesystem::signal_param_path]] = array(
|
||||
'uid' => $owner,
|
||||
'path' => $ownerPath);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -63,6 +63,8 @@ class Helper {
|
|||
|
||||
\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_delete', 'OCA\Encryption\Hooks', 'postDelete');
|
||||
\OCP\Util::connectHook('OC_Filesystem', 'delete', 'OCA\Encryption\Hooks', 'preDelete');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -214,15 +214,24 @@ class Keymanager {
|
|||
*
|
||||
* @param \OC_FilesystemView $view
|
||||
* @param string $path path of the file the key belongs to
|
||||
* @param string $userId the user to whom the file belongs
|
||||
* @return bool Outcome of unlink operation
|
||||
* @note $path must be relative to data/user/files. e.g. mydoc.txt NOT
|
||||
* /data/admin/files/mydoc.txt
|
||||
*/
|
||||
public static function deleteFileKey(\OC_FilesystemView $view, $path) {
|
||||
public static function deleteFileKey($view, $path, $userId=null) {
|
||||
|
||||
$trimmed = ltrim($path, '/');
|
||||
|
||||
$userId = Helper::getUser($path);
|
||||
if ($trimmed === '') {
|
||||
\OCP\Util::writeLog('Encryption library',
|
||||
'Can\'t delete file-key empty path given!', \OCP\Util::ERROR);
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($userId === null) {
|
||||
$userId = Helper::getUser($path);
|
||||
}
|
||||
$util = new Util($view, $userId);
|
||||
|
||||
if($util->isSystemWideMountPoint($path)) {
|
||||
|
@ -402,7 +411,15 @@ class Keymanager {
|
|||
* @param string $userId owner of the file
|
||||
* @param string $filePath path to the file, relative to the owners file dir
|
||||
*/
|
||||
public static function delAllShareKeys(\OC_FilesystemView $view, $userId, $filePath) {
|
||||
public static function delAllShareKeys($view, $userId, $filePath) {
|
||||
|
||||
$filePath = ltrim($filePath, '/');
|
||||
|
||||
if ($filePath === '') {
|
||||
\OCP\Util::writeLog('Encryption library',
|
||||
'Can\'t delete share-keys empty path given!', \OCP\Util::ERROR);
|
||||
return false;
|
||||
}
|
||||
|
||||
$util = new util($view, $userId);
|
||||
|
||||
|
@ -413,17 +430,15 @@ class Keymanager {
|
|||
}
|
||||
|
||||
|
||||
if ($view->is_dir($userId . '/files/' . $filePath)) {
|
||||
if ($view->is_dir($baseDir . $filePath)) {
|
||||
$view->unlink($baseDir . $filePath);
|
||||
} else {
|
||||
$localKeyPath = $view->getLocalFile($baseDir . $filePath);
|
||||
$escapedPath = Helper::escapeGlobPattern($localKeyPath);
|
||||
$matches = glob($escapedPath . '*.shareKey');
|
||||
foreach ($matches as $ma) {
|
||||
$result = unlink($ma);
|
||||
if (!$result) {
|
||||
\OCP\Util::writeLog('Encryption library',
|
||||
'Keyfile or shareKey could not be deleted for file "' . $filePath . '"', \OCP\Util::ERROR);
|
||||
$parentDir = dirname($baseDir . $filePath);
|
||||
$filename = pathinfo($filePath, PATHINFO_BASENAME);
|
||||
foreach($view->getDirectoryContent($parentDir) as $content) {
|
||||
$path = $content['path'];
|
||||
if (self::getFilenameFromShareKey($content['name']) === $filename) {
|
||||
$view->unlink('/' . $userId . '/' . $path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -523,4 +538,20 @@ class Keymanager {
|
|||
return $targetPath;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief extract filename from share key name
|
||||
* @param string $shareKey (filename.userid.sharekey)
|
||||
* @return mixed filename or false
|
||||
*/
|
||||
protected static function getFilenameFromShareKey($shareKey) {
|
||||
$parts = explode('.', $shareKey);
|
||||
|
||||
$filename = false;
|
||||
if(count($parts) > 2) {
|
||||
$filename = implode('.', array_slice($parts, 0, count($parts)-2));
|
||||
}
|
||||
|
||||
return $filename;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -203,47 +203,6 @@ class Proxy extends \OC_FileProxy {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief When a file is deleted, remove its keyfile also
|
||||
*/
|
||||
public function preUnlink($path) {
|
||||
|
||||
$relPath = Helper::stripUserFilesPath($path);
|
||||
|
||||
// skip this method if the trash bin is enabled or if we delete a file
|
||||
// outside of /data/user/files
|
||||
if (\OCP\App::isEnabled('files_trashbin') || $relPath === false) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Disable encryption proxy to prevent recursive calls
|
||||
$proxyStatus = \OC_FileProxy::$enabled;
|
||||
\OC_FileProxy::$enabled = false;
|
||||
|
||||
$view = new \OC_FilesystemView('/');
|
||||
|
||||
$userId = \OCP\USER::getUser();
|
||||
|
||||
$util = new Util($view, $userId);
|
||||
|
||||
list($owner, $ownerPath) = $util->getUidAndFilename($relPath);
|
||||
|
||||
// Delete keyfile & shareKey so it isn't orphaned
|
||||
if (!Keymanager::deleteFileKey($view, $ownerPath)) {
|
||||
\OCP\Util::writeLog('Encryption library',
|
||||
'Keyfile or shareKey could not be deleted for file "' . $ownerPath . '"', \OCP\Util::ERROR);
|
||||
}
|
||||
|
||||
Keymanager::delAllShareKeys($view, $owner, $ownerPath);
|
||||
|
||||
\OC_FileProxy::$enabled = $proxyStatus;
|
||||
|
||||
// If we don't return true then file delete will fail; better
|
||||
// to leave orphaned keyfiles than to disallow file deletion
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $path
|
||||
* @return bool
|
||||
|
|
|
@ -57,7 +57,7 @@ class Util {
|
|||
* @param $userId
|
||||
* @param bool $client
|
||||
*/
|
||||
public function __construct(\OC_FilesystemView $view, $userId, $client = false) {
|
||||
public function __construct($view, $userId, $client = false) {
|
||||
|
||||
$this->view = $view;
|
||||
$this->client = $client;
|
||||
|
|
271
apps/files_encryption/tests/hooks.php
Normal file
|
@ -0,0 +1,271 @@
|
|||
<?php
|
||||
/**
|
||||
* ownCloud
|
||||
*
|
||||
* @author Bjoern Schiessle
|
||||
* @copyright 2014 Bjoern Schiessle <schiessle@owncloud.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
require_once __DIR__ . '/../../../lib/base.php';
|
||||
require_once __DIR__ . '/../lib/crypt.php';
|
||||
require_once __DIR__ . '/../lib/keymanager.php';
|
||||
require_once __DIR__ . '/../lib/stream.php';
|
||||
require_once __DIR__ . '/../lib/util.php';
|
||||
require_once __DIR__ . '/../appinfo/app.php';
|
||||
require_once __DIR__ . '/util.php';
|
||||
|
||||
use OCA\Encryption;
|
||||
|
||||
/**
|
||||
* Class Test_Encryption_Hooks
|
||||
* @brief this class provide basic hook app tests
|
||||
*/
|
||||
class Test_Encryption_Hooks extends \PHPUnit_Framework_TestCase {
|
||||
|
||||
const TEST_ENCRYPTION_HOOKS_USER1 = "test-encryption-hooks-user1";
|
||||
const TEST_ENCRYPTION_HOOKS_USER2 = "test-encryption-hooks-user2";
|
||||
|
||||
/**
|
||||
* @var \OC_FilesystemView
|
||||
*/
|
||||
public $user1View; // view on /data/user1/files
|
||||
public $user2View; // view on /data/user2/files
|
||||
public $rootView; // view on /data/user
|
||||
public $data;
|
||||
public $filename;
|
||||
|
||||
public static function setUpBeforeClass() {
|
||||
// reset backend
|
||||
\OC_User::clearBackends();
|
||||
\OC_User::useBackend('database');
|
||||
|
||||
\OC_Hook::clear('OC_Filesystem');
|
||||
\OC_Hook::clear('OC_User');
|
||||
|
||||
// clear share hooks
|
||||
\OC_Hook::clear('OCP\\Share');
|
||||
\OC::registerShareHooks();
|
||||
\OCP\Util::connectHook('OC_Filesystem', 'setup', '\OC\Files\Storage\Shared', 'setup');
|
||||
|
||||
// Filesystem related hooks
|
||||
\OCA\Encryption\Helper::registerFilesystemHooks();
|
||||
|
||||
// Sharing related hooks
|
||||
\OCA\Encryption\Helper::registerShareHooks();
|
||||
|
||||
// clear and register proxies
|
||||
\OC_FileProxy::clearProxies();
|
||||
\OC_FileProxy::register(new OCA\Encryption\Proxy());
|
||||
|
||||
// create test user
|
||||
\Test_Encryption_Util::loginHelper(\Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER1, true);
|
||||
\Test_Encryption_Util::loginHelper(\Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER2, true);
|
||||
}
|
||||
|
||||
function setUp() {
|
||||
// set user id
|
||||
\Test_Encryption_Util::loginHelper(\Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER1);
|
||||
\OC_User::setUserId(\Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER1);
|
||||
|
||||
// init filesystem view
|
||||
$this->user1View = new \OC_FilesystemView('/'. \Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER1 . '/files');
|
||||
$this->user2View = new \OC_FilesystemView('/'. \Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER2 . '/files');
|
||||
$this->rootView = new \OC_FilesystemView('/');
|
||||
|
||||
// init short data
|
||||
$this->data = 'hats';
|
||||
$this->filename = 'enc_hooks_tests-' . uniqid() . '.txt';
|
||||
|
||||
}
|
||||
|
||||
public static function tearDownAfterClass() {
|
||||
// cleanup test user
|
||||
\OC_User::deleteUser(\Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER1);
|
||||
\OC_User::deleteUser(\Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER2);
|
||||
}
|
||||
|
||||
function testDeleteHooks() {
|
||||
|
||||
// remember files_trashbin state
|
||||
$stateFilesTrashbin = OC_App::isEnabled('files_trashbin');
|
||||
|
||||
// we want to tests with app files_trashbin disabled
|
||||
\OC_App::disable('files_trashbin');
|
||||
|
||||
// make sure that the trash bin is disabled
|
||||
$this->assertFalse(\OC_APP::isEnabled('files_trashbin'));
|
||||
|
||||
$this->user1View->file_put_contents($this->filename, $this->data);
|
||||
|
||||
// check if all keys are generated
|
||||
$this->assertTrue($this->rootView->file_exists(
|
||||
self::TEST_ENCRYPTION_HOOKS_USER1 . '/files_encryption/share-keys/'
|
||||
. $this->filename . '.' . \Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER1 . '.shareKey'));
|
||||
$this->assertTrue($this->rootView->file_exists(
|
||||
self::TEST_ENCRYPTION_HOOKS_USER1 . '/files_encryption/keyfiles/' . $this->filename . '.key'));
|
||||
|
||||
|
||||
\Test_Encryption_Util::logoutHelper();
|
||||
\Test_Encryption_Util::loginHelper(\Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER2);
|
||||
\OC_User::setUserId(\Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER2);
|
||||
|
||||
|
||||
$this->user2View->file_put_contents($this->filename, $this->data);
|
||||
|
||||
// check if all keys are generated
|
||||
$this->assertTrue($this->rootView->file_exists(
|
||||
self::TEST_ENCRYPTION_HOOKS_USER2 . '/files_encryption/share-keys/'
|
||||
. $this->filename . '.' . \Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER2 . '.shareKey'));
|
||||
$this->assertTrue($this->rootView->file_exists(
|
||||
self::TEST_ENCRYPTION_HOOKS_USER2 . '/files_encryption/keyfiles/' . $this->filename . '.key'));
|
||||
|
||||
|
||||
// create a dummy file that we can delete something outside of data/user/files
|
||||
// in this case no share or file keys should be deleted
|
||||
$this->rootView->file_put_contents(self::TEST_ENCRYPTION_HOOKS_USER2 . "/" . $this->filename, $this->data);
|
||||
|
||||
// delete dummy file outside of data/user/files
|
||||
$this->rootView->unlink(self::TEST_ENCRYPTION_HOOKS_USER2 . "/" . $this->filename);
|
||||
|
||||
// all keys should still exist
|
||||
$this->assertTrue($this->rootView->file_exists(
|
||||
self::TEST_ENCRYPTION_HOOKS_USER2 . '/files_encryption/share-keys/'
|
||||
. $this->filename . '.' . \Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER2 . '.shareKey'));
|
||||
$this->assertTrue($this->rootView->file_exists(
|
||||
self::TEST_ENCRYPTION_HOOKS_USER2 . '/files_encryption/keyfiles/' . $this->filename . '.key'));
|
||||
|
||||
|
||||
// delete the file in data/user/files
|
||||
// now the correspondig share and file keys from user2 should be deleted
|
||||
$this->user2View->unlink($this->filename);
|
||||
|
||||
// check if keys from user2 are really deleted
|
||||
$this->assertFalse($this->rootView->file_exists(
|
||||
self::TEST_ENCRYPTION_HOOKS_USER2 . '/files_encryption/share-keys/'
|
||||
. $this->filename . '.' . \Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER2 . '.shareKey'));
|
||||
$this->assertFalse($this->rootView->file_exists(
|
||||
self::TEST_ENCRYPTION_HOOKS_USER2 . '/files_encryption/keyfiles/' . $this->filename . '.key'));
|
||||
|
||||
// but user1 keys should still exist
|
||||
$this->assertTrue($this->rootView->file_exists(
|
||||
self::TEST_ENCRYPTION_HOOKS_USER1 . '/files_encryption/share-keys/'
|
||||
. $this->filename . '.' . \Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER1 . '.shareKey'));
|
||||
$this->assertTrue($this->rootView->file_exists(
|
||||
self::TEST_ENCRYPTION_HOOKS_USER1 . '/files_encryption/keyfiles/' . $this->filename . '.key'));
|
||||
|
||||
if ($stateFilesTrashbin) {
|
||||
OC_App::enable('files_trashbin');
|
||||
}
|
||||
else {
|
||||
OC_App::disable('files_trashbin');
|
||||
}
|
||||
}
|
||||
|
||||
function testDeleteHooksForSharedFiles() {
|
||||
|
||||
\Test_Encryption_Util::logoutHelper();
|
||||
\Test_Encryption_Util::loginHelper(\Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER1);
|
||||
\OC_User::setUserId(\Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER1);
|
||||
|
||||
// remember files_trashbin state
|
||||
$stateFilesTrashbin = OC_App::isEnabled('files_trashbin');
|
||||
|
||||
// we want to tests with app files_trashbin disabled
|
||||
\OC_App::disable('files_trashbin');
|
||||
|
||||
// make sure that the trash bin is disabled
|
||||
$this->assertFalse(\OC_APP::isEnabled('files_trashbin'));
|
||||
|
||||
$this->user1View->file_put_contents($this->filename, $this->data);
|
||||
|
||||
// check if all keys are generated
|
||||
$this->assertTrue($this->rootView->file_exists(
|
||||
self::TEST_ENCRYPTION_HOOKS_USER1 . '/files_encryption/share-keys/'
|
||||
. $this->filename . '.' . \Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER1 . '.shareKey'));
|
||||
$this->assertTrue($this->rootView->file_exists(
|
||||
self::TEST_ENCRYPTION_HOOKS_USER1 . '/files_encryption/keyfiles/' . $this->filename . '.key'));
|
||||
|
||||
// get the file info from previous created file
|
||||
$fileInfo = $this->user1View->getFileInfo($this->filename);
|
||||
|
||||
// check if we have a valid file info
|
||||
$this->assertTrue(is_array($fileInfo));
|
||||
|
||||
// share the file with user2
|
||||
\OCP\Share::shareItem('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, self::TEST_ENCRYPTION_HOOKS_USER2, OCP\PERMISSION_ALL);
|
||||
|
||||
// check if new share key exists
|
||||
$this->assertTrue($this->rootView->file_exists(
|
||||
self::TEST_ENCRYPTION_HOOKS_USER1 . '/files_encryption/share-keys/'
|
||||
. $this->filename . '.' . \Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER2 . '.shareKey'));
|
||||
|
||||
\Test_Encryption_Util::logoutHelper();
|
||||
\Test_Encryption_Util::loginHelper(\Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER2);
|
||||
\OC_User::setUserId(\Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER2);
|
||||
|
||||
// user2 has a local file with the same name
|
||||
$this->user2View->file_put_contents($this->filename, $this->data);
|
||||
|
||||
// check if all keys are generated
|
||||
$this->assertTrue($this->rootView->file_exists(
|
||||
self::TEST_ENCRYPTION_HOOKS_USER2 . '/files_encryption/share-keys/'
|
||||
. $this->filename . '.' . \Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER2 . '.shareKey'));
|
||||
$this->assertTrue($this->rootView->file_exists(
|
||||
self::TEST_ENCRYPTION_HOOKS_USER2 . '/files_encryption/keyfiles/' . $this->filename . '.key'));
|
||||
|
||||
// delete the Shared file from user1 in data/user2/files/Shared
|
||||
$this->user2View->unlink('/Shared/' . $this->filename);
|
||||
|
||||
// now keys from user1s home should be gone
|
||||
$this->assertFalse($this->rootView->file_exists(
|
||||
self::TEST_ENCRYPTION_HOOKS_USER1 . '/files_encryption/share-keys/'
|
||||
. $this->filename . '.' . \Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER1 . '.shareKey'));
|
||||
$this->assertFalse($this->rootView->file_exists(
|
||||
self::TEST_ENCRYPTION_HOOKS_USER1 . '/files_encryption/share-keys/'
|
||||
. $this->filename . '.' . \Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER2 . '.shareKey'));
|
||||
$this->assertFalse($this->rootView->file_exists(
|
||||
self::TEST_ENCRYPTION_HOOKS_USER1 . '/files_encryption/keyfiles/' . $this->filename . '.key'));
|
||||
|
||||
// but user2 keys should still exist
|
||||
$this->assertTrue($this->rootView->file_exists(
|
||||
self::TEST_ENCRYPTION_HOOKS_USER2 . '/files_encryption/share-keys/'
|
||||
. $this->filename . '.' . \Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER2 . '.shareKey'));
|
||||
$this->assertTrue($this->rootView->file_exists(
|
||||
self::TEST_ENCRYPTION_HOOKS_USER2 . '/files_encryption/keyfiles/' . $this->filename . '.key'));
|
||||
|
||||
// cleanup
|
||||
|
||||
$this->user2View->unlink($this->filename);
|
||||
|
||||
\Test_Encryption_Util::logoutHelper();
|
||||
\Test_Encryption_Util::loginHelper(\Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER1);
|
||||
\OC_User::setUserId(\Test_Encryption_Hooks::TEST_ENCRYPTION_HOOKS_USER1);
|
||||
|
||||
// unshare the file
|
||||
\OCP\Share::unshare('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_USER, self::TEST_ENCRYPTION_HOOKS_USER2);
|
||||
|
||||
$this->user1View->unlink($this->filename);
|
||||
|
||||
if ($stateFilesTrashbin) {
|
||||
OC_App::enable('files_trashbin');
|
||||
}
|
||||
else {
|
||||
OC_App::disable('files_trashbin');
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -136,6 +136,17 @@ class Test_Encryption_Keymanager extends \PHPUnit_Framework_TestCase {
|
|||
$this->assertArrayHasKey('key', $sslInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* @small
|
||||
*/
|
||||
function testGetFilenameFromShareKey() {
|
||||
$this->assertEquals("file",
|
||||
\TestProtectedKeymanagerMethods::testGetFilenameFromShareKey("file.user.shareKey"));
|
||||
$this->assertEquals("file.name.with.dots",
|
||||
\TestProtectedKeymanagerMethods::testGetFilenameFromShareKey("file.name.with.dots.user.shareKey"));
|
||||
$this->assertFalse(\TestProtectedKeymanagerMethods::testGetFilenameFromShareKey("file.txt"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @medium
|
||||
*/
|
||||
|
@ -234,3 +245,12 @@ class Test_Encryption_Keymanager extends \PHPUnit_Framework_TestCase {
|
|||
\OC_FileProxy::$enabled = $proxyStatus;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* dummy class to access protected methods of \OCA\Encryption\Keymanager for testing
|
||||
*/
|
||||
class TestProtectedKeymanagerMethods extends \OCA\Encryption\Keymanager {
|
||||
public static function testGetFilenameFromShareKey($sharekey) {
|
||||
return self::getFilenameFromShareKey($sharekey);
|
||||
}
|
||||
}
|
|
@ -112,54 +112,4 @@ class Test_Encryption_Proxy extends \PHPUnit_Framework_TestCase {
|
|||
|
||||
}
|
||||
|
||||
function testPreUnlinkWithoutTrash() {
|
||||
|
||||
// remember files_trashbin state
|
||||
$stateFilesTrashbin = OC_App::isEnabled('files_trashbin');
|
||||
|
||||
// we want to tests with app files_trashbin enabled
|
||||
\OC_App::disable('files_trashbin');
|
||||
|
||||
$this->view->file_put_contents($this->filename, $this->data);
|
||||
|
||||
// create a dummy file that we can delete something outside of data/user/files
|
||||
$this->rootView->file_put_contents("dummy.txt", $this->data);
|
||||
|
||||
// check if all keys are generated
|
||||
$this->assertTrue($this->rootView->file_exists(
|
||||
'/files_encryption/share-keys/'
|
||||
. $this->filename . '.' . \Test_Encryption_Proxy::TEST_ENCRYPTION_PROXY_USER1 . '.shareKey'));
|
||||
$this->assertTrue($this->rootView->file_exists(
|
||||
'/files_encryption/keyfiles/' . $this->filename . '.key'));
|
||||
|
||||
|
||||
// delete dummy file outside of data/user/files
|
||||
$this->rootView->unlink("dummy.txt");
|
||||
|
||||
// all keys should still exist
|
||||
$this->assertTrue($this->rootView->file_exists(
|
||||
'/files_encryption/share-keys/'
|
||||
. $this->filename . '.' . \Test_Encryption_Proxy::TEST_ENCRYPTION_PROXY_USER1 . '.shareKey'));
|
||||
$this->assertTrue($this->rootView->file_exists(
|
||||
'/files_encryption/keyfiles/' . $this->filename . '.key'));
|
||||
|
||||
|
||||
// delete the file in data/user/files
|
||||
$this->view->unlink($this->filename);
|
||||
|
||||
// now also the keys should be gone
|
||||
$this->assertFalse($this->rootView->file_exists(
|
||||
'/files_encryption/share-keys/'
|
||||
. $this->filename . '.' . \Test_Encryption_Proxy::TEST_ENCRYPTION_PROXY_USER1 . '.shareKey'));
|
||||
$this->assertFalse($this->rootView->file_exists(
|
||||
'/files_encryption/keyfiles/' . $this->filename . '.key'));
|
||||
|
||||
if ($stateFilesTrashbin) {
|
||||
OC_App::enable('files_trashbin');
|
||||
}
|
||||
else {
|
||||
OC_App::disable('files_trashbin');
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -194,8 +194,9 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase {
|
|||
. $this->filename . '.' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '.shareKey'));
|
||||
|
||||
// cleanup
|
||||
$this->view->unlink(
|
||||
'/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files/' . $this->filename);
|
||||
$this->view->chroot('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files/');
|
||||
$this->view->unlink($this->filename);
|
||||
$this->view->chroot('/');
|
||||
|
||||
// check if share key not exists
|
||||
$this->assertFalse($this->view->file_exists(
|
||||
|
@ -265,8 +266,9 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase {
|
|||
. $this->filename . '.' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '.shareKey'));
|
||||
|
||||
// cleanup
|
||||
$this->view->unlink(
|
||||
'/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files/' . $this->filename);
|
||||
$this->view->chroot('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files/');
|
||||
$this->view->unlink($this->filename);
|
||||
$this->view->chroot('/');
|
||||
|
||||
// check if share key not exists
|
||||
$this->assertFalse($this->view->file_exists(
|
||||
|
@ -352,7 +354,9 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase {
|
|||
. $this->filename . '.' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '.shareKey'));
|
||||
|
||||
// cleanup
|
||||
$this->view->unlink('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files' . $this->folder1);
|
||||
$this->view->chroot('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files');
|
||||
$this->view->unlink($this->folder1);
|
||||
$this->view->chroot('/');
|
||||
|
||||
// check if share key not exists
|
||||
$this->assertFalse($this->view->file_exists(
|
||||
|
@ -482,9 +486,9 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase {
|
|||
. $this->filename . '.' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '.shareKey'));
|
||||
|
||||
// cleanup
|
||||
$this->view->unlink(
|
||||
'/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files' . $this->folder1 . $this->subfolder
|
||||
. $this->subsubfolder . '/' . $this->filename);
|
||||
$this->view->chroot('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files');
|
||||
$this->view->unlink($this->folder1 . $this->subfolder . $this->subsubfolder . '/' . $this->filename);
|
||||
$this->view->chroot('/');
|
||||
|
||||
// check if share key not exists
|
||||
$this->assertFalse($this->view->file_exists(
|
||||
|
@ -559,7 +563,9 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase {
|
|||
. $this->filename . '.' . $publicShareKeyId . '.shareKey'));
|
||||
|
||||
// cleanup
|
||||
$this->view->unlink('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files/' . $this->filename);
|
||||
$this->view->chroot('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files/');
|
||||
$this->view->unlink($this->filename);
|
||||
$this->view->chroot('/');
|
||||
|
||||
// check if share key not exists
|
||||
$this->assertFalse($this->view->file_exists(
|
||||
|
@ -636,7 +642,9 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase {
|
|||
. $this->filename . '.' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER4 . '.shareKey'));
|
||||
|
||||
// cleanup
|
||||
$this->view->unlink('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files/' . $this->filename);
|
||||
$this->view->chroot('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files/');
|
||||
$this->view->unlink($this->filename);
|
||||
$this->view->chroot('/');
|
||||
|
||||
// check if share key not exists
|
||||
$this->assertFalse($this->view->file_exists(
|
||||
|
@ -731,8 +739,10 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase {
|
|||
. $this->filename . '.' . $recoveryKeyId . '.shareKey'));
|
||||
|
||||
// cleanup
|
||||
$this->view->unlink('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files/' . $this->filename);
|
||||
$this->view->unlink('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files/' . $this->folder1);
|
||||
$this->view->chroot('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files/');
|
||||
$this->view->unlink($this->filename);
|
||||
$this->view->unlink($this->folder1);
|
||||
$this->view->chroot('/');
|
||||
|
||||
// check if share key for recovery not exists
|
||||
$this->assertFalse($this->view->file_exists(
|
||||
|
@ -828,8 +838,10 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase {
|
|||
$this->assertEquals($this->dataShort, $retrievedCryptedFile2);
|
||||
|
||||
// cleanup
|
||||
$this->view->unlink('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '/files/' . $this->folder1);
|
||||
$this->view->unlink('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '/files/' . $this->filename);
|
||||
$this->view->chroot('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER2 . '/files/');
|
||||
$this->view->unlink($this->folder1);
|
||||
$this->view->unlink($this->filename);
|
||||
$this->view->chroot('/');
|
||||
|
||||
// check if share key for user and recovery exists
|
||||
$this->assertFalse($this->view->file_exists(
|
||||
|
@ -930,7 +942,9 @@ class Test_Encryption_Share extends \PHPUnit_Framework_TestCase {
|
|||
. $this->filename . '.' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER3 . '.shareKey'));
|
||||
|
||||
// cleanup
|
||||
$this->view->unlink('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files/' . $this->filename);
|
||||
$this->view->chroot('/' . \Test_Encryption_Share::TEST_ENCRYPTION_SHARE_USER1 . '/files/');
|
||||
$this->view->unlink($this->filename);
|
||||
$this->view->chroot('/');
|
||||
}
|
||||
|
||||
}
|
||||
|
|
49
apps/files_sharing/css/mobile.css
Normal file
|
@ -0,0 +1,49 @@
|
|||
@media only screen and (max-width: 600px) {
|
||||
|
||||
/* make header scroll up for single shares, more view of content on small screens */
|
||||
#header.share-file {
|
||||
position: absolute !important;
|
||||
}
|
||||
|
||||
/* hide size and date columns */
|
||||
table th#headerSize,
|
||||
table td.filesize,
|
||||
table th#headerDate,
|
||||
table td.date {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* restrict length of displayed filename to prevent overflow */
|
||||
table td.filename .nametext {
|
||||
max-width: 75% !important;
|
||||
}
|
||||
|
||||
/* on mobile, show single shared image at full width without margin */
|
||||
#imgframe {
|
||||
width: 100%;
|
||||
padding: 0;
|
||||
margin-bottom: 35px;
|
||||
}
|
||||
/* some margin for the file type icon */
|
||||
#imgframe .publicpreview {
|
||||
margin-top: 32px;
|
||||
}
|
||||
|
||||
/* always show actions on mobile */
|
||||
#fileList a.action {
|
||||
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=20)" !important;
|
||||
filter: alpha(opacity=20) !important;
|
||||
opacity: .2 !important;
|
||||
display: inline !important;
|
||||
}
|
||||
/* some padding for better clickability */
|
||||
#fileList a.action img {
|
||||
padding: 0 6px 0 12px;
|
||||
}
|
||||
/* hide text of the actions on mobile */
|
||||
#fileList a.action span {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -14,39 +14,17 @@ body {
|
|||
padding:7px;
|
||||
}
|
||||
|
||||
#details {
|
||||
color:#fff;
|
||||
float: left;
|
||||
}
|
||||
|
||||
#public_upload,
|
||||
#download {
|
||||
font-weight:700;
|
||||
margin: 0 0 0 6px;
|
||||
padding: 0 5px;
|
||||
height: 32px;
|
||||
float: left;
|
||||
|
||||
}
|
||||
|
||||
.header-right #details {
|
||||
margin-right: 28px;
|
||||
}
|
||||
|
||||
.header-right {
|
||||
padding: 0;
|
||||
height: 32px;
|
||||
}
|
||||
|
||||
#public_upload {
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
#public_upload img,
|
||||
#download img {
|
||||
padding-left:2px;
|
||||
padding-right:5px;
|
||||
vertical-align:text-bottom;
|
||||
#details {
|
||||
color:#fff;
|
||||
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=50)";
|
||||
filter: alpha(opacity=50);
|
||||
opacity: .5;
|
||||
padding-right: 5px;
|
||||
}
|
||||
|
||||
#controls {
|
||||
|
@ -71,9 +49,8 @@ footer {
|
|||
p.info {
|
||||
color: #777;
|
||||
text-align: center;
|
||||
width: 352px;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
padding: 20px 0;
|
||||
}
|
||||
|
||||
p.info a {
|
||||
|
@ -94,9 +71,13 @@ p.info a {
|
|||
max-width:100%;
|
||||
}
|
||||
|
||||
thead{
|
||||
background-color: white;
|
||||
padding-left:0 !important; /* fixes multiselect bar offset on shared page */
|
||||
/* some margin for the file type icon */
|
||||
#imgframe .publicpreview {
|
||||
margin-top: 10%;
|
||||
}
|
||||
|
||||
thead {
|
||||
padding-left: 0 !important; /* fixes multiselect bar offset on shared page */
|
||||
}
|
||||
|
||||
#data-upload-form {
|
||||
|
@ -110,27 +91,20 @@ thead{
|
|||
margin: 0;
|
||||
}
|
||||
|
||||
#file_upload_start {
|
||||
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";
|
||||
filter: alpha(opacity=0);
|
||||
opacity: 0;
|
||||
z-index: 20;
|
||||
position: absolute !important;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100% !important;
|
||||
}
|
||||
|
||||
.directDownload,
|
||||
.directLink {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.directDownload .button img {
|
||||
vertical-align: text-bottom;
|
||||
}
|
||||
.directLink label {
|
||||
font-weight: normal;
|
||||
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=50)";
|
||||
filter: alpha(opacity=50);
|
||||
opacity: .5;
|
||||
}
|
||||
.directLink input {
|
||||
margin-left: 10px;
|
||||
margin-left: 5px;
|
||||
width: 300px;
|
||||
}
|
||||
.public_actions {
|
||||
padding: 4px;
|
||||
}
|
||||
|
|
|
@ -9,22 +9,13 @@ function fileDownloadPath(dir, file) {
|
|||
|
||||
$(document).ready(function() {
|
||||
|
||||
$('#data-upload-form').tipsy({gravity:'ne', fade:true});
|
||||
|
||||
if (typeof FileActions !== 'undefined') {
|
||||
var mimetype = $('#mimetype').val();
|
||||
// Show file preview if previewer is available, images are already handled by the template
|
||||
if (mimetype.substr(0, mimetype.indexOf('/')) != 'image' && $('.publicpreview').length === 0) {
|
||||
// Trigger default action if not download TODO
|
||||
var action = FileActions.getDefault(mimetype, 'file', OC.PERMISSION_READ);
|
||||
if (typeof action === 'undefined') {
|
||||
$('#noPreview').show();
|
||||
if (mimetype != 'httpd/unix-directory') {
|
||||
// NOTE: Remove when a better file previewer solution exists
|
||||
$('#content').remove();
|
||||
$('table').remove();
|
||||
}
|
||||
} else {
|
||||
if (typeof action !== 'undefined') {
|
||||
action($('#filename').val());
|
||||
}
|
||||
}
|
||||
|
@ -34,18 +25,16 @@ $(document).ready(function() {
|
|||
window.location = $(tr).find('a.name').attr('href');
|
||||
}
|
||||
});
|
||||
FileActions.register('file', 'Download', OC.PERMISSION_READ, '', function(filename) {
|
||||
|
||||
// override since the format is different
|
||||
FileList.getDownloadUrl = function(filename, dir) {
|
||||
// we use this because we need the service and token attributes
|
||||
var tr = FileList.findFileEl(filename);
|
||||
if (tr.length > 0) {
|
||||
window.location = $(tr).find('a.name').attr('href');
|
||||
return $(tr).find('a.name').attr('href') + '&download';
|
||||
}
|
||||
});
|
||||
FileActions.register('dir', 'Download', OC.PERMISSION_READ, '', function(filename) {
|
||||
var tr = FileList.findFileEl(filename);
|
||||
if (tr.length > 0) {
|
||||
window.location = $(tr).find('a.name').attr('href')+'&download';
|
||||
}
|
||||
});
|
||||
return null;
|
||||
};
|
||||
}
|
||||
|
||||
var file_upload_start = $('#file_upload_start');
|
||||
|
@ -58,16 +47,9 @@ $(document).ready(function() {
|
|||
};
|
||||
});
|
||||
|
||||
// Add Uploadprogress Wrapper to controls bar
|
||||
$('#controls').append($('#controls .actions div#uploadprogresswrapper'));
|
||||
$('#uploadprogresswrapper').addClass('public_actions');
|
||||
|
||||
// Cancel upload trigger
|
||||
$('#cancel_upload_button').click(function() {
|
||||
OC.Upload.cancelUploads();
|
||||
procesSelection();
|
||||
$(document).on('click', '#directLink', function() {
|
||||
$(this).focus();
|
||||
$(this).select();
|
||||
});
|
||||
|
||||
$('#directLink').focus();
|
||||
|
||||
});
|
||||
|
|
|
@ -162,7 +162,7 @@ class Api {
|
|||
$view = new \OC\Files\View('/'.\OCP\User::getUser().'/files');
|
||||
|
||||
if(!$view->is_dir($path)) {
|
||||
return new \OC_OCS_Result(null, 404, "not a directory");
|
||||
return new \OC_OCS_Result(null, 400, "not a directory");
|
||||
}
|
||||
|
||||
$content = $view->getDirectoryContent($path);
|
||||
|
@ -178,8 +178,7 @@ class Api {
|
|||
$share['received_from_displayname'] = \OCP\User::getDisplayName($receivedFrom['uid_owner']);
|
||||
}
|
||||
if ($share) {
|
||||
$share['filename'] = $file['name'];
|
||||
$result[] = $share;
|
||||
$result = array_merge($result, $share);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -220,10 +219,8 @@ class Api {
|
|||
$shareWith = isset($_POST['password']) ? $_POST['password'] : null;
|
||||
//check public link share
|
||||
$publicUploadEnabled = \OC_Appconfig::getValue('core', 'shareapi_allow_public_upload', 'yes');
|
||||
$encryptionEnabled = \OC_App::isEnabled('files_encryption');
|
||||
if(isset($_POST['publicUpload']) &&
|
||||
($encryptionEnabled || $publicUploadEnabled !== 'yes')) {
|
||||
return new \OC_OCS_Result(null, 404, "public upload disabled by the administrator");
|
||||
if(isset($_POST['publicUpload']) && $publicUploadEnabled !== 'yes') {
|
||||
return new \OC_OCS_Result(null, 403, "public upload disabled by the administrator");
|
||||
}
|
||||
$publicUpload = isset($_POST['publicUpload']) ? $_POST['publicUpload'] : 'false';
|
||||
// read, create, update (7) if public upload is enabled or
|
||||
|
@ -231,7 +228,7 @@ class Api {
|
|||
$permissions = $publicUpload === 'true' ? 7 : 1;
|
||||
break;
|
||||
default:
|
||||
return new \OC_OCS_Result(null, 404, "unknown share type");
|
||||
return new \OC_OCS_Result(null, 400, "unknown share type");
|
||||
}
|
||||
|
||||
try {
|
||||
|
@ -243,7 +240,7 @@ class Api {
|
|||
$permissions
|
||||
);
|
||||
} catch (\Exception $e) {
|
||||
return new \OC_OCS_Result(null, 404, $e->getMessage());
|
||||
return new \OC_OCS_Result(null, 403, $e->getMessage());
|
||||
}
|
||||
|
||||
if ($token) {
|
||||
|
@ -321,11 +318,8 @@ class Api {
|
|||
$permissions = isset($params['_put']['permissions']) ? (int)$params['_put']['permissions'] : null;
|
||||
|
||||
$publicUploadStatus = \OC_Appconfig::getValue('core', 'shareapi_allow_public_upload', 'yes');
|
||||
$encryptionEnabled = \OC_App::isEnabled('files_encryption');
|
||||
$publicUploadEnabled = false;
|
||||
if(!$encryptionEnabled && $publicUploadStatus === 'yes') {
|
||||
$publicUploadEnabled = true;
|
||||
}
|
||||
$publicUploadEnabled = ($publicUploadStatus === 'yes') ? true : false;
|
||||
|
||||
|
||||
// only change permissions for public shares if public upload is enabled
|
||||
// and we want to set permissions to 1 (read only) or 7 (allow upload)
|
||||
|
@ -363,9 +357,8 @@ class Api {
|
|||
private static function updatePublicUpload($share, $params) {
|
||||
|
||||
$publicUploadEnabled = \OC_Appconfig::getValue('core', 'shareapi_allow_public_upload', 'yes');
|
||||
$encryptionEnabled = \OC_App::isEnabled('files_encryption');
|
||||
if($encryptionEnabled || $publicUploadEnabled !== 'yes') {
|
||||
return new \OC_OCS_Result(null, 404, "public upload disabled by the administrator");
|
||||
if($publicUploadEnabled !== 'yes') {
|
||||
return new \OC_OCS_Result(null, 403, "public upload disabled by the administrator");
|
||||
}
|
||||
|
||||
if ($share['item_type'] !== 'folder' ||
|
||||
|
|
|
@ -92,12 +92,11 @@ class Shared_Cache extends Cache {
|
|||
} else {
|
||||
$query = \OC_DB::prepare(
|
||||
'SELECT `fileid`, `storage`, `path`, `parent`, `name`, `mimetype`, `mimepart`,'
|
||||
.' `size`, `mtime`, `encrypted`'
|
||||
.' `size`, `mtime`, `encrypted`, `unencrypted_size`'
|
||||
.' FROM `*PREFIX*filecache` WHERE `fileid` = ?');
|
||||
$result = $query->execute(array($file));
|
||||
$data = $result->fetchRow();
|
||||
$data['fileid'] = (int)$data['fileid'];
|
||||
$data['size'] = (int)$data['size'];
|
||||
$data['mtime'] = (int)$data['mtime'];
|
||||
$data['storage_mtime'] = (int)$data['storage_mtime'];
|
||||
$data['encrypted'] = (bool)$data['encrypted'];
|
||||
|
@ -106,6 +105,12 @@ class Shared_Cache extends Cache {
|
|||
if ($data['storage_mtime'] === 0) {
|
||||
$data['storage_mtime'] = $data['mtime'];
|
||||
}
|
||||
if ($data['encrypted'] or ($data['unencrypted_size'] > 0 and $data['mimetype'] === 'httpd/unix-directory')) {
|
||||
$data['encrypted_size'] = (int)$data['size'];
|
||||
$data['size'] = (int)$data['unencrypted_size'];
|
||||
} else {
|
||||
$data['size'] = (int)$data['size'];
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
return false;
|
||||
|
@ -259,17 +264,38 @@ class Shared_Cache extends Cache {
|
|||
* @return array
|
||||
*/
|
||||
public function searchByMime($mimetype) {
|
||||
|
||||
if (strpos($mimetype, '/')) {
|
||||
$where = '`mimetype` = ? AND ';
|
||||
} else {
|
||||
$where = '`mimepart` = ? AND ';
|
||||
$mimepart = null;
|
||||
if (strpos($mimetype, '/') === false) {
|
||||
$mimepart = $mimetype;
|
||||
$mimetype = null;
|
||||
}
|
||||
|
||||
$value = $this->getMimetypeId($mimetype);
|
||||
|
||||
return $this->searchWithWhere($where, $value);
|
||||
// note: searchWithWhere is currently broken as it doesn't
|
||||
// recurse into subdirs nor returns the correct
|
||||
// file paths, so using getFolderContents() for now
|
||||
|
||||
$result = array();
|
||||
$exploreDirs = array('');
|
||||
while (count($exploreDirs) > 0) {
|
||||
$dir = array_pop($exploreDirs);
|
||||
$files = $this->getFolderContents($dir);
|
||||
// no results?
|
||||
if (!$files) {
|
||||
continue;
|
||||
}
|
||||
foreach ($files as $file) {
|
||||
if ($file['mimetype'] === 'httpd/unix-directory') {
|
||||
$exploreDirs[] = ltrim($dir . '/' . $file['name'], '/');
|
||||
}
|
||||
else if (($mimepart && $file['mimepart'] === $mimepart) || ($mimetype && $file['mimetype'] === $mimetype)) {
|
||||
// usersPath not reliable
|
||||
//$file['path'] = $file['usersPath'];
|
||||
$file['path'] = ltrim($dir . '/' . $file['name'], '/');
|
||||
$result[] = $file;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -313,6 +339,12 @@ class Shared_Cache extends Cache {
|
|||
}
|
||||
$row['mimetype'] = $this->getMimetype($row['mimetype']);
|
||||
$row['mimepart'] = $this->getMimetype($row['mimepart']);
|
||||
if ($row['encrypted'] or ($row['unencrypted_size'] > 0 and $row['mimetype'] === 'httpd/unix-directory')) {
|
||||
$row['encrypted_size'] = $row['size'];
|
||||
$row['size'] = $row['unencrypted_size'];
|
||||
} else {
|
||||
$row['size'] = $row['size'];
|
||||
}
|
||||
$files[] = $row;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -91,10 +91,17 @@ class OC_Share_Backend_File implements OCP\Share_Backend_File_Dependent {
|
|||
$file['name'] = basename($item['file_target']);
|
||||
$file['mimetype'] = $item['mimetype'];
|
||||
$file['mimepart'] = $item['mimepart'];
|
||||
$file['size'] = $item['size'];
|
||||
$file['mtime'] = $item['mtime'];
|
||||
$file['encrypted'] = $item['encrypted'];
|
||||
$file['etag'] = $item['etag'];
|
||||
$storage = \OC\Files\Filesystem::getStorage('/');
|
||||
$cache = $storage->getCache();
|
||||
if ($item['encrypted'] or ($item['unencrypted_size'] > 0 and $cache->getMimetype($item['mimetype']) === 'httpd/unix-directory')) {
|
||||
$file['size'] = $item['unencrypted_size'];
|
||||
$file['encrypted_size'] = $item['size'];
|
||||
} else {
|
||||
$file['size'] = $item['size'];
|
||||
}
|
||||
$files[] = $file;
|
||||
}
|
||||
return $files;
|
||||
|
|
|
@ -137,21 +137,19 @@ if (isset($path)) {
|
|||
} else {
|
||||
OCP\Util::addScript('files', 'file-upload');
|
||||
OCP\Util::addStyle('files_sharing', 'public');
|
||||
OCP\Util::addStyle('files_sharing', 'mobile');
|
||||
OCP\Util::addScript('files_sharing', 'public');
|
||||
OCP\Util::addScript('files', 'fileactions');
|
||||
OCP\Util::addScript('files', 'jquery.iframe-transport');
|
||||
OCP\Util::addScript('files', 'jquery.fileupload');
|
||||
$maxUploadFilesize=OCP\Util::maxUploadFilesize($path);
|
||||
$tmpl = new OCP\Template('files_sharing', 'public', 'base');
|
||||
$tmpl->assign('uidOwner', $shareOwner);
|
||||
$tmpl->assign('displayName', \OCP\User::getDisplayName($shareOwner));
|
||||
$tmpl->assign('filename', $file);
|
||||
$tmpl->assign('directory_path', $linkItem['file_target']);
|
||||
$tmpl->assign('mimetype', \OC\Files\Filesystem::getMimeType($path));
|
||||
$tmpl->assign('fileTarget', basename($linkItem['file_target']));
|
||||
$tmpl->assign('dirToken', $linkItem['token']);
|
||||
$tmpl->assign('sharingToken', $token);
|
||||
$tmpl->assign('disableSharing', true);
|
||||
$allowPublicUploadEnabled = (bool) ($linkItem['permissions'] & OCP\PERMISSION_CREATE);
|
||||
if (OC_Appconfig::getValue('core', 'shareapi_allow_public_upload', 'yes') === 'no') {
|
||||
$allowPublicUploadEnabled = false;
|
||||
|
@ -159,9 +157,6 @@ if (isset($path)) {
|
|||
if ($linkItem['item_type'] !== 'folder') {
|
||||
$allowPublicUploadEnabled = false;
|
||||
}
|
||||
$tmpl->assign('allowPublicUploadEnabled', $allowPublicUploadEnabled);
|
||||
$tmpl->assign('uploadMaxFilesize', $maxUploadFilesize);
|
||||
$tmpl->assign('uploadMaxHumanFilesize', OCP\Util::humanFileSize($maxUploadFilesize));
|
||||
|
||||
$urlLinkIdentifiers= (isset($token)?'&t='.$token:'')
|
||||
.(isset($_GET['dir'])?'&dir='.$_GET['dir']:'')
|
||||
|
@ -222,17 +217,23 @@ if (isset($path)) {
|
|||
$maxUploadFilesize=OCP\Util::maxUploadFilesize($path);
|
||||
$fileHeader = (!isset($files) or count($files) > 0);
|
||||
$emptyContent = ($allowPublicUploadEnabled and !$fileHeader);
|
||||
|
||||
$freeSpace=OCP\Util::freeSpace($path);
|
||||
$uploadLimit=OCP\Util::uploadLimit();
|
||||
$folder = new OCP\Template('files', 'index', '');
|
||||
$folder->assign('fileList', $list->fetchPage());
|
||||
$folder->assign('breadcrumb', $breadcrumbNav->fetchPage());
|
||||
$folder->assign('dir', $getPath);
|
||||
$folder->assign('isCreatable', false);
|
||||
$folder->assign('isCreatable', $allowPublicUploadEnabled);
|
||||
$folder->assign('dirToken', $linkItem['token']);
|
||||
$folder->assign('permissions', OCP\PERMISSION_READ);
|
||||
$folder->assign('isPublic',true);
|
||||
$folder->assign('publicUploadEnabled', 'no');
|
||||
$folder->assign('files', $files);
|
||||
$folder->assign('uploadMaxFilesize', $maxUploadFilesize);
|
||||
$folder->assign('uploadMaxHumanFilesize', OCP\Util::humanFileSize($maxUploadFilesize));
|
||||
$folder->assign('freeSpace', $freeSpace);
|
||||
$folder->assign('uploadLimit', $uploadLimit); // PHP upload limit
|
||||
$folder->assign('allowZipDownload', intval(OCP\Config::getSystemValue('allowZipDownload', true)));
|
||||
$folder->assign('usedSpacePercent', 0);
|
||||
$folder->assign('fileHeader', $fileHeader);
|
||||
|
|
|
@ -9,54 +9,14 @@
|
|||
<input type="hidden" name="sharingToken" value="<?php p($_['sharingToken']) ?>" id="sharingToken">
|
||||
<input type="hidden" name="filename" value="<?php p($_['filename']) ?>" id="filename">
|
||||
<input type="hidden" name="mimetype" value="<?php p($_['mimetype']) ?>" id="mimetype">
|
||||
<header><div id="header" class="icon icon-noise">
|
||||
<header><div id="header" class="icon icon-noise <?php p((isset($_['folder']) ? 'share-folder' : 'share-file')) ?>">
|
||||
<a href="<?php print_unescaped(link_to('', 'index.php')); ?>" title="" id="owncloud"><img class="svg"
|
||||
src="<?php print_unescaped(image_path('', 'logo-wide.svg')); ?>" alt="<?php p($theme->getName()); ?>" /></a>
|
||||
<div id="logo-claim" style="display:none;"><?php p($theme->getLogoClaim()); ?></div>
|
||||
<div class="header-right">
|
||||
<?php if (isset($_['folder'])): ?>
|
||||
<span id="details"><?php p($l->t('%s shared the folder %s with you',
|
||||
array($_['displayName'], $_['filename']))) ?></span>
|
||||
<?php else: ?>
|
||||
<span id="details"><?php p($l->t('%s shared the file %s with you',
|
||||
array($_['displayName'], $_['filename']))) ?></span>
|
||||
<?php endif; ?>
|
||||
|
||||
|
||||
<?php if (!isset($_['folder']) || $_['allowZipDownload']): ?>
|
||||
<a href="<?php p($_['downloadURL']); ?>" class="button" id="download">
|
||||
<img class="svg" alt="Download" src="<?php print_unescaped(OCP\image_path("core", "actions/download.svg")); ?>" />
|
||||
<span><?php p($l->t('Download'))?></span>
|
||||
</a>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($_['allowPublicUploadEnabled']):?>
|
||||
|
||||
|
||||
<input type="hidden" id="publicUploadRequestToken" name="requesttoken" value="<?php p($_['requesttoken']) ?>" />
|
||||
<input type="hidden" id="dirToken" name="dirToken" value="<?php p($_['dirToken']) ?>" />
|
||||
<input type="hidden" id="uploadMaxFilesize" name="uploadMaxFilesize" value="<?php p($_['uploadMaxFilesize']) ?>" />
|
||||
<input type="hidden" id="uploadMaxHumanFilesize" name="uploadMaxHumanFilesize" value="<?php p($_['uploadMaxHumanFilesize']) ?>" />
|
||||
<input type="hidden" id="directory_path" name="directory_path" value="<?php p($_['directory_path']) ?>" />
|
||||
<?php if($_['uploadMaxFilesize'] >= 0):?>
|
||||
<input type="hidden" name="MAX_FILE_SIZE" id="max_upload"
|
||||
value="<?php p($_['uploadMaxFilesize']) ?>">
|
||||
<?php endif;?>
|
||||
|
||||
|
||||
<div id="data-upload-form" title="<?php p($l->t('Upload') . ' max. '.$_['uploadMaxHumanFilesize']) ?>">
|
||||
<input id="file_upload_start" type="file" name="files[]" data-url="<?php print_unescaped(OCP\Util::linkTo('files', 'ajax/upload.php')); ?>" multiple>
|
||||
<a href="#" id="public_upload" class="button">
|
||||
<img class="svg" alt="Upload" src="<?php print_unescaped(OCP\image_path("core", "actions/upload.svg")); ?>" />
|
||||
<span><?php p($l->t('Upload'))?></span>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<span id="details"><?php p($l->t('shared by %s', array($_['displayName']))) ?></span>
|
||||
</div>
|
||||
<div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div></header>
|
||||
</div></header>
|
||||
<div id="content">
|
||||
<div id="preview">
|
||||
<?php if (isset($_['folder'])): ?>
|
||||
|
@ -72,25 +32,28 @@
|
|||
<source src="<?php p($_['downloadURL']); ?>" type="<?php p($_['mimetype']); ?>" />
|
||||
</video>
|
||||
</div>
|
||||
<?php elseif (\OC\Preview::isMimeSupported($_['mimetype'])): ?>
|
||||
<div id="imgframe">
|
||||
<img src="<?php p(OCP\Util::linkToRoute( 'core_ajax_public_preview', array('x' => 500, 'y' => 500, 'file' => urlencode($_['directory_path']), 't' => $_['dirToken']))); ?>" class="publicpreview"/>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<ul id="noPreview">
|
||||
<li class="error">
|
||||
<?php p($l->t('No preview available for').' '.$_['filename']); ?><br />
|
||||
<a href="<?php p($_['downloadURL']); ?>" id="download"><img class="svg" alt="Download"
|
||||
src="<?php print_unescaped(OCP\image_path("core", "actions/download.svg")); ?>"
|
||||
/><?php p($l->t('Download'))?></a>
|
||||
</li>
|
||||
</ul>
|
||||
<div id="imgframe">
|
||||
<?php $size = \OC\Preview::isMimeSupported($_['mimetype']) ? 500 : 128 ?>
|
||||
<img src="<?php p(OCP\Util::linkToRoute( 'core_ajax_public_preview', array('x' => $size, 'y' => $size, 'file' => urlencode($_['directory_path']), 't' => $_['dirToken']))); ?>" class="publicpreview"/>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<div class="directLink"><label for="directLink"><?php p($l->t('Direct link')) ?></label><input id="directLink" type="text" readonly value="<?php p($_['downloadURL']); ?>"></input></div>
|
||||
<div class="directDownload">
|
||||
<a href="<?php p($_['downloadURL']); ?>" id="download" class="button">
|
||||
<img class="svg" alt="" src="<?php print_unescaped(OCP\image_path("core", "actions/download.svg")); ?>"/>
|
||||
<?php p($l->t('Download %s', array($_['filename'])))?>
|
||||
</a>
|
||||
</div>
|
||||
<div class="directLink">
|
||||
<label for="directLink"><?php p($l->t('Direct link')) ?></label>
|
||||
<input id="directLink" type="text" readonly value="<?php p($_['downloadURL']); ?>">
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<footer>
|
||||
<p class="info">
|
||||
<?php print_unescaped($theme->getLongFooter()); ?>
|
||||
</p>
|
||||
</footer>
|
||||
|
||||
</div>
|
||||
<footer>
|
||||
<p class="info">
|
||||
<?php print_unescaped($theme->getLongFooter()); ?>
|
||||
</p>
|
||||
</footer>
|
||||
|
|
134
apps/files_sharing/tests/cache.php
Normal file
|
@ -0,0 +1,134 @@
|
|||
<?php
|
||||
/**
|
||||
* ownCloud
|
||||
*
|
||||
* @author Vincent Petry
|
||||
* @copyright 2014 Vincent Petry <pvince81@owncloud.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
require_once __DIR__ . '/base.php';
|
||||
|
||||
class Test_Files_Sharing_Cache extends Test_Files_Sharing_Base {
|
||||
|
||||
function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
self::loginHelper(self::TEST_FILES_SHARING_API_USER1);
|
||||
|
||||
// prepare user1's dir structure
|
||||
$textData = "dummy file data\n";
|
||||
$this->view->mkdir('container');
|
||||
$this->view->mkdir('container/shareddir');
|
||||
$this->view->mkdir('container/shareddir/subdir');
|
||||
$this->view->mkdir('container/shareddir/emptydir');
|
||||
|
||||
$textData = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
||||
$this->view->file_put_contents('container/not shared.txt', $textData);
|
||||
$this->view->file_put_contents('container/shared single file.txt', $textData);
|
||||
$this->view->file_put_contents('container/shareddir/bar.txt', $textData);
|
||||
$this->view->file_put_contents('container/shareddir/subdir/another.txt', $textData);
|
||||
$this->view->file_put_contents('container/shareddir/subdir/another too.txt', $textData);
|
||||
$this->view->file_put_contents('container/shareddir/subdir/not a text file.xml', '<xml></xml>');
|
||||
|
||||
list($this->ownerStorage, $internalPath) = $this->view->resolvePath('');
|
||||
$this->ownerCache = $this->ownerStorage->getCache();
|
||||
$this->ownerStorage->getScanner()->scan('');
|
||||
|
||||
// share "shareddir" with user2
|
||||
$fileinfo = $this->view->getFileInfo('container/shareddir');
|
||||
\OCP\Share::shareItem('folder', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_USER,
|
||||
self::TEST_FILES_SHARING_API_USER2, 31);
|
||||
|
||||
$fileinfo = $this->view->getFileInfo('container/shared single file.txt');
|
||||
\OCP\Share::shareItem('file', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_USER,
|
||||
self::TEST_FILES_SHARING_API_USER2, 31);
|
||||
|
||||
// login as user2
|
||||
self::loginHelper(self::TEST_FILES_SHARING_API_USER2);
|
||||
|
||||
// retrieve the shared storage
|
||||
$secondView = new \OC\Files\View('/' . self::TEST_FILES_SHARING_API_USER2);
|
||||
list($this->sharedStorage, $internalPath) = $secondView->resolvePath('files/Shared/shareddir');
|
||||
$this->sharedCache = $this->sharedStorage->getCache();
|
||||
}
|
||||
|
||||
function tearDown() {
|
||||
$this->sharedCache->clear();
|
||||
|
||||
self::loginHelper(self::TEST_FILES_SHARING_API_USER1);
|
||||
|
||||
$fileinfo = $this->view->getFileInfo('container/shareddir');
|
||||
\OCP\Share::unshare('folder', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_USER,
|
||||
self::TEST_FILES_SHARING_API_USER2);
|
||||
|
||||
$fileinfo = $this->view->getFileInfo('container/shared single file.txt');
|
||||
\OCP\Share::unshare('file', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_USER,
|
||||
self::TEST_FILES_SHARING_API_USER2);
|
||||
|
||||
$this->view->deleteAll('container');
|
||||
|
||||
$this->ownerCache->clear();
|
||||
|
||||
parent::tearDown();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test searching by mime type
|
||||
*/
|
||||
function testSearchByMime() {
|
||||
$results = $this->sharedStorage->getCache()->searchByMime('text');
|
||||
$check = array(
|
||||
array(
|
||||
'name' => 'shared single file.txt',
|
||||
'path' => 'shared single file.txt'
|
||||
),
|
||||
array(
|
||||
'name' => 'bar.txt',
|
||||
'path' => 'shareddir/bar.txt'
|
||||
),
|
||||
array(
|
||||
'name' => 'another too.txt',
|
||||
'path' => 'shareddir/subdir/another too.txt'
|
||||
),
|
||||
array(
|
||||
'name' => 'another.txt',
|
||||
'path' => 'shareddir/subdir/another.txt'
|
||||
),
|
||||
);
|
||||
$this->verifyFiles($check, $results);
|
||||
|
||||
$results2 = $this->sharedStorage->getCache()->searchByMime('text/plain');
|
||||
|
||||
$this->verifyFiles($check, $results);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that all provided attributes exist in the files list,
|
||||
* only the values provided in $examples will be used to check against
|
||||
* the file list. The files order also needs to be the same.
|
||||
*
|
||||
* @param array $examples array of example files
|
||||
* @param array $files array of files
|
||||
*/
|
||||
private function verifyFiles($examples, $files) {
|
||||
$this->assertEquals(count($examples), count($files));
|
||||
foreach ($files as $i => $file) {
|
||||
foreach ($examples[$i] as $key => $value) {
|
||||
$this->assertEquals($value, $file[$key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -34,7 +34,17 @@ try{
|
|||
if ($view->is_dir($file)) {
|
||||
$mimetype = 'httpd/unix-directory';
|
||||
} else {
|
||||
$mimetype = \OC_Helper::getFileNameMimeType(pathinfo($file, PATHINFO_FILENAME));
|
||||
$pathInfo = pathinfo($file);
|
||||
$fileName = $pathInfo['basename'];
|
||||
// if in root dir
|
||||
if ($pathInfo['dirname'] === '.') {
|
||||
// cut off the .d* suffix
|
||||
$i = strrpos($fileName, '.');
|
||||
if ($i !== false) {
|
||||
$fileName = substr($fileName, 0, $i);
|
||||
}
|
||||
}
|
||||
$mimetype = \OC_Helper::getFileNameMimeType($fileName);
|
||||
}
|
||||
$preview->setMimetype($mimetype);
|
||||
$preview->setMaxX($maxX);
|
||||
|
@ -45,4 +55,4 @@ try{
|
|||
}catch(\Exception $e) {
|
||||
\OC_Response::setStatus(500);
|
||||
\OC_Log::write('core', $e->getmessage(), \OC_Log::DEBUG);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -52,7 +52,7 @@ class Connection extends LDAPUtility {
|
|||
$this->configID = $configID;
|
||||
$this->configuration = new Configuration($configPrefix,
|
||||
!is_null($configID));
|
||||
$memcache = new \OC\Memcache\Factory();
|
||||
$memcache = \OC::$server->getMemCacheFactory();
|
||||
if($memcache->isAvailable()) {
|
||||
$this->cache = $memcache->create();
|
||||
} else {
|
||||
|
|
|
@ -33,5 +33,5 @@ then
|
|||
exit 2
|
||||
fi
|
||||
|
||||
KARMA_TESTSUITE="$1" $KARMA start tests/karma.config.js --single-run
|
||||
NODE_PATH='build/node_modules' KARMA_TESTSUITE="$1" $KARMA start tests/karma.config.js --single-run
|
||||
|
||||
|
|
|
@ -185,19 +185,23 @@ EOF
|
|||
cp $BASEDIR/tests/autoconfig-$1.php $BASEDIR/config/autoconfig.php
|
||||
|
||||
# trigger installation
|
||||
php -f index.php
|
||||
echo "INDEX"
|
||||
php -f index.php | grep -i -C9999 error && echo "Error during setup" && exit 101
|
||||
echo "END INDEX"
|
||||
|
||||
#test execution
|
||||
echo "Testing with $1 ..."
|
||||
cd tests
|
||||
rm -rf coverage-html-$1
|
||||
mkdir coverage-html-$1
|
||||
php -f enable_all.php
|
||||
php -f enable_all.php | grep -i -C9999 error && echo "Error during setup" && exit 101
|
||||
if [ -z "$NOCOVERAGE" ]; then
|
||||
$PHPUNIT --configuration phpunit-autotest.xml --log-junit autotest-results-$1.xml --coverage-clover autotest-clover-$1.xml --coverage-html coverage-html-$1 $2 $3
|
||||
RESULT=$?
|
||||
else
|
||||
echo "No coverage"
|
||||
$PHPUNIT --configuration phpunit-autotest.xml --log-junit autotest-results-$1.xml $2 $3
|
||||
RESULT=$?
|
||||
fi
|
||||
}
|
||||
|
||||
|
|
|
@ -184,6 +184,13 @@ $CONFIG = array(
|
|||
/* Life time of a session after inactivity */
|
||||
"session_lifetime" => 60 * 60 * 24,
|
||||
|
||||
/*
|
||||
* Enable/disable session keep alive when a user is logged in in the Web UI.
|
||||
* This is achieved by sending a "heartbeat" to the server to prevent
|
||||
* the session timing out.
|
||||
*/
|
||||
"session_keepalive" => true,
|
||||
|
||||
/* Custom CSP policy, changing this will overwrite the standard policy */
|
||||
"custom_csp_policy" => "default-src 'self'; script-src 'self' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; frame-src *; img-src *; font-src 'self' data:; media-src *",
|
||||
|
||||
|
|
|
@ -121,7 +121,7 @@ if (isset($_POST['action']) && isset($_POST['itemType']) && isset($_POST['itemSo
|
|||
if (isset($items[0]['expiration'])) {
|
||||
try {
|
||||
$date = new DateTime($items[0]['expiration']);
|
||||
$expiration = $date->format('Y-m-d');
|
||||
$expiration = $l->l('date', $date->getTimestamp());
|
||||
} catch (Exception $e) {
|
||||
\OCP\Util::writeLog('sharing', "Couldn't read date: " . $e->getMessage(), \OCP\Util::ERROR);
|
||||
}
|
||||
|
@ -187,6 +187,8 @@ if (isset($_POST['action']) && isset($_POST['itemType']) && isset($_POST['itemSo
|
|||
break;
|
||||
|
||||
case 'email':
|
||||
// enable l10n support
|
||||
$l = OC_L10N::get('core');
|
||||
// read post variables
|
||||
$user = OCP\USER::getUser();
|
||||
$displayName = OCP\User::getDisplayName();
|
||||
|
@ -199,16 +201,13 @@ if (isset($_POST['action']) && isset($_POST['itemType']) && isset($_POST['itemSo
|
|||
if (isset($_POST['expiration']) && $_POST['expiration'] !== '') {
|
||||
try {
|
||||
$date = new DateTime($_POST['expiration']);
|
||||
$expiration = $date->format('Y-m-d');
|
||||
$expiration = $l->l('date', $date->getTimestamp());
|
||||
} catch (Exception $e) {
|
||||
\OCP\Util::writeLog('sharing', "Couldn't read date: " . $e->getMessage(), \OCP\Util::ERROR);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// enable l10n support
|
||||
$l = OC_L10N::get('core');
|
||||
|
||||
// setup the email
|
||||
$subject = (string)$l->t('%s shared »%s« with you', array($displayName, $file));
|
||||
|
||||
|
|
|
@ -47,6 +47,10 @@
|
|||
background-image: url('../img/actions/checkmark.svg');
|
||||
}
|
||||
|
||||
.icon-checkmark-white {
|
||||
background-image: url('../img/actions/checkmark-white.svg');
|
||||
}
|
||||
|
||||
.icon-clock {
|
||||
background-image: url('../img/actions/clock.svg');
|
||||
}
|
||||
|
|
|
@ -686,7 +686,7 @@ label.infield { cursor:text !important; top:1.05em; left:.85em; }
|
|||
/* Apps management as sticky footer, less obtrusive in the list */
|
||||
#navigation .wrapper {
|
||||
min-height: 100%;
|
||||
margin: 0 auto -72px;
|
||||
margin: 0 auto -82px 0;
|
||||
}
|
||||
#apps-management, #navigation .push {
|
||||
height: 72px;
|
||||
|
|
BIN
core/img/actions/checkmark-white.png
Normal file
After Width: | Height: | Size: 286 B |
4
core/img/actions/checkmark-white.svg
Normal file
|
@ -0,0 +1,4 @@
|
|||
<svg xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" version="1.1" xml:space="preserve" height="16px" viewBox="-0.5 -0.5 16 16" width="16px" enable-background="new -0.5 -0.5 16 16" y="0px" x="0px" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" overflow="visible"><metadata><rdf:RDF><cc:Work rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/><dc:title/></cc:Work></rdf:RDF></metadata><defs>
|
||||
</defs>
|
||||
<path fill="#ffffff" d="M12.438,3.6875c-0.363,0-0.726,0.1314-1,0.4063l-4.5005,4.5-1.9687-2c-0.5498-0.5484-1.4489-0.5498-2,0l-0.5,0.5c-0.5512,0.5496-0.5512,1.4502,0,2l2.9687,2.9682c0.0063,0.007-0.0065,0.025,0,0.032l0.5,0.5c0.5497,0.55,1.4503,0.55,2,0l0.5-0.5,0.1875-0.219,5.313-5.2812c0.549-0.5498,0.549-1.4503,0-2l-0.5-0.5c-0.275-0.2749-0.638-0.4063-1-0.4063z" transform="translate(-0.5,-0.5)"/>
|
||||
</svg>
|
After Width: | Height: | Size: 946 B |
BIN
core/img/actions/toggle-filelist.png
Normal file
After Width: | Height: | Size: 195 B |
11
core/img/actions/toggle-filelist.svg
Normal file
|
@ -0,0 +1,11 @@
|
|||
<?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/">
|
||||
<g>
|
||||
<rect rx=".5" ry=".5" height="4" width="4" y="1" x="1"/>
|
||||
<rect rx=".5" ry=".5" height="1" width="9" y="2" x="6"/>
|
||||
<rect rx=".5" ry=".5" height="4" width="4" y="6" x="1"/>
|
||||
<rect rx=".5" ry=".5" height="1" width="9" y="7" x="6"/>
|
||||
<rect rx=".5" ry=".5" height="4" width="4" y="11" x="1"/>
|
||||
<rect rx=".5" ry=".5" height="1" width="9" y="12" x="6"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 692 B |
BIN
core/img/actions/toggle-pictures.png
Normal file
After Width: | Height: | Size: 193 B |
9
core/img/actions/toggle-pictures.svg
Normal file
|
@ -0,0 +1,9 @@
|
|||
<?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/">
|
||||
<g>
|
||||
<rect rx=".5" ry=".5" height="6" width="6" y="1" x="1"/>
|
||||
<rect rx=".5" ry=".5" height="6" width="6" y="1" x="9"/>
|
||||
<rect rx=".5" ry=".5" height="6" width="6" y="9" x="9"/>
|
||||
<rect rx=".5" ry=".5" height="6" width="6" y="9" x="1"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 572 B |
Before Width: | Height: | Size: 242 B After Width: | Height: | Size: 434 B |
|
@ -1,7 +1,4 @@
|
|||
<?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="32" width="32" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/">
|
||||
<g transform="translate(581.71 -2.0765)">
|
||||
<path style="block-progression:tb;text-indent:0;color:#000000;text-transform:none" d="m-575.01 3.0806c-0.39495 0.0765-0.70712 0.46665-0.70001 0.87488l-0.00062 26.246c0.00001 0.45808 0.41045 0.87487 0.86155 0.87488h20.28c0.4511-0.000012 0.86154-0.4168 0.86155-0.87488l0.00061-25.921c-0.00065-0.67287-0.53099-1.2037-1.0337-1.1998h-20.27zm1.2998 19.996h18l0.00082 6h-18.001z"/>
|
||||
<path style="block-progression:tb;text-indent:0;color:#000000;text-transform:none" d="m-575.01 4.0806c-0.39495 0.0765-0.70712 0.46665-0.70001 0.87488l-0.00062 26.246c0.00001 0.45808 0.41045 0.87487 0.86155 0.87488h20.28c0.4511-0.000012 0.86154-0.4168 0.86155-0.87488l0.00061-25.921c-0.00065-0.67287-0.53099-1.2037-1.0337-1.1998h-20.27zm1.2998 19.996h18l0.00082 6h-18.001z" fill="#fff"/>
|
||||
</g>
|
||||
<path style="block-progression:tb;color:#000000;text-transform:none;text-indent:0" fill="#fff" d="m0.6875 4c-0.39495 0.0765-0.69461 0.4668-0.6875 0.875v22.25c0.00001 0.458 0.4239 0.875 0.875 0.875h30.25c0.4511-0.000012 0.87499-0.41692 0.875-0.875v-21.906c-0.001-0.6731-0.529-1.2229-1.031-1.219zm2.3125 3h26v10l-2-2-5 7-6.625-4-9.1875 7h-3.1875zm6 3c-1.6569 0-3 1.3431-3 3s1.3431 3 3 3 3-1.3431 3-3-1.3431-3-3-3z"/>
|
||||
</svg>
|
||||
|
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 698 B |
|
@ -55,6 +55,12 @@ $array = array(
|
|||
)
|
||||
),
|
||||
"firstDay" => json_encode($l->l('firstday', 'firstday')) ,
|
||||
"oc_config" => json_encode(
|
||||
array(
|
||||
'session_lifetime' => \OCP\Config::getSystemValue('session_lifetime', 60 * 60 * 24),
|
||||
'session_keepalive' => \OCP\Config::getSystemValue('session_keepalive', true)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
// Echo it
|
||||
|
|
|
@ -1,28 +1,23 @@
|
|||
{
|
||||
"libraries": [
|
||||
"jquery-1.10.0.min.js",
|
||||
"jquery-migrate-1.2.1.min.js",
|
||||
"jquery-ui-1.10.0.custom.js",
|
||||
"jquery-showpassword.js",
|
||||
"jquery.infieldlabel.js",
|
||||
"jquery.placeholder.js",
|
||||
"jquery-tipsy.js"
|
||||
],
|
||||
"modules": [
|
||||
"jquery-1.10.0.min.js",
|
||||
"jquery-migrate-1.2.1.min.js",
|
||||
"jquery-ui-1.10.0.custom.js",
|
||||
"jquery-showpassword.js",
|
||||
"jquery.infieldlabel.js",
|
||||
"jquery.placeholder.js",
|
||||
"jquery-tipsy.js",
|
||||
"compatibility.js",
|
||||
"jquery.ocdialog.js",
|
||||
"oc-dialogs.js",
|
||||
"js.js",
|
||||
"octemplate.js",
|
||||
"eventsource.js",
|
||||
"config.js",
|
||||
"multiselect.js",
|
||||
"search.js",
|
||||
"router.js",
|
||||
"oc-requesttoken.js",
|
||||
"styles.js",
|
||||
"apps.js",
|
||||
"fixes.js",
|
||||
"jquery-ui-2.10.0.custom.js",
|
||||
"jquery-tipsy.js",
|
||||
"jquery.ocdialog.js"
|
||||
"compatibility.js",
|
||||
"jquery.ocdialog.js",
|
||||
"oc-dialogs.js",
|
||||
"js.js",
|
||||
"octemplate.js",
|
||||
"eventsource.js",
|
||||
"config.js",
|
||||
"multiselect.js",
|
||||
"router.js",
|
||||
"oc-requesttoken.js"
|
||||
]
|
||||
}
|
||||
|
|
|
@ -11,6 +11,8 @@ var oc_webroot;
|
|||
var oc_current_user = document.getElementsByTagName('head')[0].getAttribute('data-user');
|
||||
var oc_requesttoken = document.getElementsByTagName('head')[0].getAttribute('data-requesttoken');
|
||||
|
||||
window.oc_config = window.oc_config || {};
|
||||
|
||||
if (typeof oc_webroot === "undefined") {
|
||||
oc_webroot = location.pathname;
|
||||
var pos = oc_webroot.indexOf('/index.php/');
|
||||
|
@ -252,6 +254,12 @@ var OC={
|
|||
}
|
||||
return link;
|
||||
},
|
||||
/**
|
||||
* Redirect to the target URL, can also be used for downloads.
|
||||
*/
|
||||
redirect: function(targetUrl) {
|
||||
window.location = targetUrl;
|
||||
},
|
||||
/**
|
||||
* get the absolute path to an image file
|
||||
* @param app the app id to which the image belongs
|
||||
|
@ -364,6 +372,34 @@ var OC={
|
|||
}
|
||||
return result;
|
||||
},
|
||||
|
||||
/**
|
||||
* Builds a URL query from a JS map.
|
||||
* @param params parameter map
|
||||
* @return string containing a URL query (without question) mark
|
||||
*/
|
||||
buildQueryString: function(params) {
|
||||
var s = '';
|
||||
var first = true;
|
||||
if (!params) {
|
||||
return s;
|
||||
}
|
||||
for (var key in params) {
|
||||
var value = params[key];
|
||||
if (first) {
|
||||
first = false;
|
||||
}
|
||||
else {
|
||||
s += '&';
|
||||
}
|
||||
s += encodeURIComponent(key);
|
||||
if (value !== null && typeof(value) !== 'undefined') {
|
||||
s += '=' + encodeURIComponent(value);
|
||||
}
|
||||
}
|
||||
return s;
|
||||
},
|
||||
|
||||
/**
|
||||
* Opens a popup with the setting for an app.
|
||||
* @param appid String. The ID of the app e.g. 'calendar', 'contacts' or 'files'.
|
||||
|
@ -708,8 +744,39 @@ function fillWindow(selector) {
|
|||
console.warn("This function is deprecated! Use CSS instead");
|
||||
}
|
||||
|
||||
$(document).ready(function(){
|
||||
sessionHeartBeat();
|
||||
/**
|
||||
* Initializes core
|
||||
*/
|
||||
function initCore() {
|
||||
|
||||
/**
|
||||
* Calls the server periodically to ensure that session doesn't
|
||||
* time out
|
||||
*/
|
||||
function initSessionHeartBeat(){
|
||||
// interval in seconds
|
||||
var interval = 900;
|
||||
if (oc_config.session_lifetime) {
|
||||
interval = Math.floor(oc_config.session_lifetime / 2);
|
||||
}
|
||||
// minimum one minute
|
||||
if (interval < 60) {
|
||||
interval = 60;
|
||||
}
|
||||
OC.Router.registerLoadedCallback(function(){
|
||||
var url = OC.Router.generate('heartbeat');
|
||||
setInterval(function(){
|
||||
$.post(url);
|
||||
}, interval * 1000);
|
||||
});
|
||||
}
|
||||
|
||||
// session heartbeat (defaults to enabled)
|
||||
if (typeof(oc_config.session_keepalive) === 'undefined' ||
|
||||
!!oc_config.session_keepalive) {
|
||||
|
||||
initSessionHeartBeat();
|
||||
}
|
||||
|
||||
if(!SVGSupport()){ //replace all svg images with png images for browser that dont support svg
|
||||
replaceSVG();
|
||||
|
@ -822,7 +889,9 @@ $(document).ready(function(){
|
|||
$('input[type=text]').focus(function(){
|
||||
this.select();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
$(document).ready(initCore);
|
||||
|
||||
/**
|
||||
* Filter Jquery selector by attribute value
|
||||
|
@ -952,15 +1021,3 @@ jQuery.fn.exists = function(){
|
|||
return this.length > 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Calls the server periodically every 15 mins to ensure that session doesnt
|
||||
* time out
|
||||
*/
|
||||
function sessionHeartBeat(){
|
||||
OC.Router.registerLoadedCallback(function(){
|
||||
var url = OC.Router.generate('heartbeat');
|
||||
setInterval(function(){
|
||||
$.post(url);
|
||||
}, 900000);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
*
|
||||
*/
|
||||
|
||||
/* global OC */
|
||||
|
||||
/**
|
||||
* Simulate the variables that are normally set by PHP code
|
||||
*/
|
||||
|
@ -57,10 +59,15 @@ window.oc_webroot = location.href + '/';
|
|||
window.oc_appswebroots = {
|
||||
"files": window.oc_webroot + '/apps/files/'
|
||||
};
|
||||
window.oc_config = {
|
||||
session_lifetime: 600 * 1000,
|
||||
session_keepalive: false
|
||||
};
|
||||
|
||||
// global setup for all tests
|
||||
(function setupTests() {
|
||||
var fakeServer = null;
|
||||
var fakeServer = null,
|
||||
routesRequestStub;
|
||||
|
||||
beforeEach(function() {
|
||||
// enforce fake XHR, tests should not depend on the server and
|
||||
|
@ -78,9 +85,18 @@ window.oc_appswebroots = {
|
|||
// make it globally available, so that other tests can define
|
||||
// custom responses
|
||||
window.fakeServer = fakeServer;
|
||||
|
||||
OC.Router.routes = [];
|
||||
OC.Router.routes_request = {
|
||||
state: sinon.stub().returns('resolved'),
|
||||
done: sinon.stub()
|
||||
};
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
OC.Router.routes_request.state.reset();
|
||||
OC.Router.routes_request.done.reset();
|
||||
|
||||
// uncomment this to log requests
|
||||
// console.log(window.fakeServer.requests);
|
||||
fakeServer.restore();
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/* global OC */
|
||||
describe('Core base tests', function() {
|
||||
describe('Base values', function() {
|
||||
it('Sets webroots', function() {
|
||||
|
@ -25,6 +27,103 @@ describe('Core base tests', function() {
|
|||
expect(OC.appswebroots).toBeDefined();
|
||||
});
|
||||
});
|
||||
describe('basename', function() {
|
||||
it('Returns the nothing if no file name given', function() {
|
||||
expect(OC.basename('')).toEqual('');
|
||||
});
|
||||
it('Returns the nothing if dir is root', function() {
|
||||
expect(OC.basename('/')).toEqual('');
|
||||
});
|
||||
it('Returns the same name if no path given', function() {
|
||||
expect(OC.basename('some name.txt')).toEqual('some name.txt');
|
||||
});
|
||||
it('Returns the base name if root path given', function() {
|
||||
expect(OC.basename('/some name.txt')).toEqual('some name.txt');
|
||||
});
|
||||
it('Returns the base name if double root path given', function() {
|
||||
expect(OC.basename('//some name.txt')).toEqual('some name.txt');
|
||||
});
|
||||
it('Returns the base name if subdir given without root', function() {
|
||||
expect(OC.basename('subdir/some name.txt')).toEqual('some name.txt');
|
||||
});
|
||||
it('Returns the base name if subdir given with root', function() {
|
||||
expect(OC.basename('/subdir/some name.txt')).toEqual('some name.txt');
|
||||
});
|
||||
it('Returns the base name if subdir given with double root', function() {
|
||||
expect(OC.basename('//subdir/some name.txt')).toEqual('some name.txt');
|
||||
});
|
||||
it('Returns the base name if subdir has dot', function() {
|
||||
expect(OC.basename('/subdir.dat/some name.txt')).toEqual('some name.txt');
|
||||
});
|
||||
it('Returns dot if file name is dot', function() {
|
||||
expect(OC.basename('/subdir/.')).toEqual('.');
|
||||
});
|
||||
// TODO: fix the source to make it work like PHP's basename
|
||||
it('Returns the dir itself if no file name given', function() {
|
||||
// TODO: fix the source to make it work like PHP's dirname
|
||||
// expect(OC.basename('subdir/')).toEqual('subdir');
|
||||
expect(OC.basename('subdir/')).toEqual('');
|
||||
});
|
||||
it('Returns the dir itself if no file name given with root', function() {
|
||||
// TODO: fix the source to make it work like PHP's dirname
|
||||
// expect(OC.basename('/subdir/')).toEqual('subdir');
|
||||
expect(OC.basename('/subdir/')).toEqual('');
|
||||
});
|
||||
});
|
||||
describe('dirname', function() {
|
||||
it('Returns the nothing if no file name given', function() {
|
||||
expect(OC.dirname('')).toEqual('');
|
||||
});
|
||||
it('Returns the root if dir is root', function() {
|
||||
// TODO: fix the source to make it work like PHP's dirname
|
||||
// expect(OC.dirname('/')).toEqual('/');
|
||||
expect(OC.dirname('/')).toEqual('');
|
||||
});
|
||||
it('Returns the root if dir is double root', function() {
|
||||
// TODO: fix the source to make it work like PHP's dirname
|
||||
// expect(OC.dirname('//')).toEqual('/');
|
||||
expect(OC.dirname('//')).toEqual('/'); // oh no...
|
||||
});
|
||||
it('Returns dot if dir is dot', function() {
|
||||
expect(OC.dirname('.')).toEqual('.');
|
||||
});
|
||||
it('Returns dot if no root given', function() {
|
||||
// TODO: fix the source to make it work like PHP's dirname
|
||||
// expect(OC.dirname('some dir')).toEqual('.');
|
||||
expect(OC.dirname('some dir')).toEqual('some dir'); // oh no...
|
||||
});
|
||||
it('Returns the dir name if file name and root path given', function() {
|
||||
// TODO: fix the source to make it work like PHP's dirname
|
||||
// expect(OC.dirname('/some name.txt')).toEqual('/');
|
||||
expect(OC.dirname('/some name.txt')).toEqual('');
|
||||
});
|
||||
it('Returns the dir name if double root path given', function() {
|
||||
expect(OC.dirname('//some name.txt')).toEqual('/'); // how lucky...
|
||||
});
|
||||
it('Returns the dir name if subdir given without root', function() {
|
||||
expect(OC.dirname('subdir/some name.txt')).toEqual('subdir');
|
||||
});
|
||||
it('Returns the dir name if subdir given with root', function() {
|
||||
expect(OC.dirname('/subdir/some name.txt')).toEqual('/subdir');
|
||||
});
|
||||
it('Returns the dir name if subdir given with double root', function() {
|
||||
// TODO: fix the source to make it work like PHP's dirname
|
||||
// expect(OC.dirname('//subdir/some name.txt')).toEqual('/subdir');
|
||||
expect(OC.dirname('//subdir/some name.txt')).toEqual('//subdir'); // oh...
|
||||
});
|
||||
it('Returns the dir name if subdir has dot', function() {
|
||||
expect(OC.dirname('/subdir.dat/some name.txt')).toEqual('/subdir.dat');
|
||||
});
|
||||
it('Returns the dir name if file name is dot', function() {
|
||||
expect(OC.dirname('/subdir/.')).toEqual('/subdir');
|
||||
});
|
||||
it('Returns the dir name if no file name given', function() {
|
||||
expect(OC.dirname('subdir/')).toEqual('subdir');
|
||||
});
|
||||
it('Returns the dir name if no file name given with root', function() {
|
||||
expect(OC.dirname('/subdir/')).toEqual('/subdir');
|
||||
});
|
||||
});
|
||||
describe('Link functions', function() {
|
||||
var TESTAPP = 'testapp';
|
||||
var TESTAPP_ROOT = OC.webroot + '/appsx/testapp';
|
||||
|
@ -67,4 +166,115 @@ describe('Core base tests', function() {
|
|||
});
|
||||
});
|
||||
});
|
||||
describe('Query string building', function() {
|
||||
it('Returns empty string when empty params', function() {
|
||||
expect(OC.buildQueryString()).toEqual('');
|
||||
expect(OC.buildQueryString({})).toEqual('');
|
||||
});
|
||||
it('Encodes regular query strings', function() {
|
||||
expect(OC.buildQueryString({
|
||||
a: 'abc',
|
||||
b: 'def'
|
||||
})).toEqual('a=abc&b=def');
|
||||
});
|
||||
it('Encodes special characters', function() {
|
||||
expect(OC.buildQueryString({
|
||||
unicode: '汉字',
|
||||
})).toEqual('unicode=%E6%B1%89%E5%AD%97');
|
||||
expect(OC.buildQueryString({
|
||||
b: 'spaace value',
|
||||
'space key': 'normalvalue',
|
||||
'slash/this': 'amp&ersand'
|
||||
})).toEqual('b=spaace%20value&space%20key=normalvalue&slash%2Fthis=amp%26ersand');
|
||||
});
|
||||
it('Encodes data types and empty values', function() {
|
||||
expect(OC.buildQueryString({
|
||||
'keywithemptystring': '',
|
||||
'keywithnull': null,
|
||||
'keywithundefined': null,
|
||||
something: 'else'
|
||||
})).toEqual('keywithemptystring=&keywithnull&keywithundefined&something=else');
|
||||
expect(OC.buildQueryString({
|
||||
'booleanfalse': false,
|
||||
'booleantrue': true
|
||||
})).toEqual('booleanfalse=false&booleantrue=true');
|
||||
expect(OC.buildQueryString({
|
||||
'number': 123,
|
||||
})).toEqual('number=123');
|
||||
});
|
||||
});
|
||||
describe('Session heartbeat', function() {
|
||||
var clock,
|
||||
oldConfig,
|
||||
loadedStub,
|
||||
routeStub,
|
||||
counter;
|
||||
|
||||
beforeEach(function() {
|
||||
clock = sinon.useFakeTimers();
|
||||
oldConfig = window.oc_config;
|
||||
loadedStub = sinon.stub(OC.Router, 'registerLoadedCallback');
|
||||
routeStub = sinon.stub(OC.Router, 'generate').returns('/heartbeat');
|
||||
counter = 0;
|
||||
|
||||
fakeServer.autoRespond = true;
|
||||
fakeServer.autoRespondAfter = 0;
|
||||
fakeServer.respondWith(/\/heartbeat/, function(xhr) {
|
||||
counter++;
|
||||
xhr.respond(200, {'Content-Type': 'application/json'}, '{}');
|
||||
});
|
||||
});
|
||||
afterEach(function() {
|
||||
clock.restore();
|
||||
window.oc_config = oldConfig;
|
||||
loadedStub.restore();
|
||||
routeStub.restore();
|
||||
});
|
||||
it('sends heartbeat half the session lifetime when heartbeat enabled', function() {
|
||||
window.oc_config = {
|
||||
session_keepalive: true,
|
||||
session_lifetime: 300
|
||||
};
|
||||
window.initCore();
|
||||
expect(loadedStub.calledOnce).toEqual(true);
|
||||
loadedStub.yield();
|
||||
expect(routeStub.calledWith('heartbeat')).toEqual(true);
|
||||
|
||||
expect(counter).toEqual(0);
|
||||
|
||||
// less than half, still nothing
|
||||
clock.tick(100 * 1000);
|
||||
expect(counter).toEqual(0);
|
||||
|
||||
// reach past half (160), one call
|
||||
clock.tick(55 * 1000);
|
||||
expect(counter).toEqual(1);
|
||||
|
||||
// almost there to the next, still one
|
||||
clock.tick(140 * 1000);
|
||||
expect(counter).toEqual(1);
|
||||
|
||||
// past it, second call
|
||||
clock.tick(20 * 1000);
|
||||
expect(counter).toEqual(2);
|
||||
});
|
||||
it('does no send heartbeat when heartbeat disabled', function() {
|
||||
window.oc_config = {
|
||||
session_keepalive: false,
|
||||
session_lifetime: 300
|
||||
};
|
||||
window.initCore();
|
||||
expect(loadedStub.notCalled).toEqual(true);
|
||||
expect(routeStub.notCalled).toEqual(true);
|
||||
|
||||
expect(counter).toEqual(0);
|
||||
|
||||
clock.tick(1000000);
|
||||
|
||||
// still nothing
|
||||
expect(counter).toEqual(0);
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -1,73 +0,0 @@
|
|||
<?php
|
||||
|
||||
// Check for autosetup:
|
||||
$autosetup_file = OC::$SERVERROOT."/config/autoconfig.php";
|
||||
if( file_exists( $autosetup_file )) {
|
||||
OC_Log::write('core', 'Autoconfig file found, setting up owncloud...', OC_Log::INFO);
|
||||
include $autosetup_file;
|
||||
$_POST = array_merge ($_POST, $AUTOCONFIG);
|
||||
$_REQUEST = array_merge ($_REQUEST, $AUTOCONFIG);
|
||||
}
|
||||
|
||||
$dbIsSet = isset($_POST['dbtype']);
|
||||
$directoryIsSet = isset($_POST['directory']);
|
||||
$adminAccountIsSet = isset($_POST['adminlogin']);
|
||||
|
||||
if ($dbIsSet AND $directoryIsSet AND $adminAccountIsSet) {
|
||||
$_POST['install'] = 'true';
|
||||
if( file_exists( $autosetup_file )) {
|
||||
unlink($autosetup_file);
|
||||
}
|
||||
}
|
||||
|
||||
OC_Util::addScript( '3rdparty', 'strengthify/jquery.strengthify' );
|
||||
OC_Util::addStyle( '3rdparty', 'strengthify/strengthify' );
|
||||
OC_Util::addScript('setup');
|
||||
|
||||
$hasSQLite = class_exists('SQLite3');
|
||||
$hasMySQL = is_callable('mysql_connect');
|
||||
$hasPostgreSQL = is_callable('pg_connect');
|
||||
$hasOracle = is_callable('oci_connect');
|
||||
$hasMSSQL = is_callable('sqlsrv_connect');
|
||||
$datadir = OC_Config::getValue('datadirectory', OC::$SERVERROOT.'/data');
|
||||
$vulnerableToNullByte = false;
|
||||
if(@file_exists(__FILE__."\0Nullbyte")) { // Check if the used PHP version is vulnerable to the NULL Byte attack (CVE-2006-7243)
|
||||
$vulnerableToNullByte = true;
|
||||
}
|
||||
|
||||
// Protect data directory here, so we can test if the protection is working
|
||||
OC_Setup::protectDataDirectory();
|
||||
|
||||
$opts = array(
|
||||
'hasSQLite' => $hasSQLite,
|
||||
'hasMySQL' => $hasMySQL,
|
||||
'hasPostgreSQL' => $hasPostgreSQL,
|
||||
'hasOracle' => $hasOracle,
|
||||
'hasMSSQL' => $hasMSSQL,
|
||||
'directory' => $datadir,
|
||||
'secureRNG' => OC_Util::secureRNGAvailable(),
|
||||
'htaccessWorking' => OC_Util::isHtAccessWorking(),
|
||||
'vulnerableToNullByte' => $vulnerableToNullByte,
|
||||
'errors' => array(),
|
||||
'dbIsSet' => $dbIsSet,
|
||||
'directoryIsSet' => $directoryIsSet,
|
||||
);
|
||||
|
||||
if(isset($_POST['install']) AND $_POST['install']=='true') {
|
||||
// We have to launch the installation process :
|
||||
$e = OC_Setup::install($_POST);
|
||||
$errors = array('errors' => $e);
|
||||
|
||||
if(count($e) > 0) {
|
||||
//OC_Template::printGuestPage("", "error", array("errors" => $errors));
|
||||
$options = array_merge($_POST, $opts, $errors);
|
||||
OC_Template::printGuestPage("", "installation", $options);
|
||||
}
|
||||
else {
|
||||
header( 'Location: '.OC_Helper::linkToRoute( 'post_setup_check' ));
|
||||
exit();
|
||||
}
|
||||
}
|
||||
else {
|
||||
OC_Template::printGuestPage("", "installation", $opts);
|
||||
}
|
139
core/setup/controller.php
Normal file
|
@ -0,0 +1,139 @@
|
|||
<?php
|
||||
/**
|
||||
* Copyright (c) 2013 Bart Visscher <bartv@thisnet.nl>
|
||||
* This file is licensed under the Affero General Public License version 3 or
|
||||
* later.
|
||||
* See the COPYING-README file.
|
||||
*/
|
||||
|
||||
namespace OC\Core\Setup;
|
||||
|
||||
class Controller {
|
||||
public function run($post) {
|
||||
// Check for autosetup:
|
||||
$post = $this->loadAutoConfig($post);
|
||||
$opts = $this->getSystemInfo();
|
||||
|
||||
if(isset($post['install']) AND $post['install']=='true') {
|
||||
// We have to launch the installation process :
|
||||
$e = \OC_Setup::install($post);
|
||||
$errors = array('errors' => $e);
|
||||
|
||||
if(count($e) > 0) {
|
||||
$options = array_merge($post, $opts, $errors);
|
||||
$this->display($options);
|
||||
}
|
||||
else {
|
||||
$this->finishSetup();
|
||||
}
|
||||
}
|
||||
else {
|
||||
$this->display($opts);
|
||||
}
|
||||
}
|
||||
|
||||
public function display($post) {
|
||||
$defaults = array(
|
||||
'adminlogin' => '',
|
||||
'adminpass' => '',
|
||||
'dbuser' => '',
|
||||
'dbpass' => '',
|
||||
'dbname' => '',
|
||||
'dbtablespace' => '',
|
||||
'dbhost' => '',
|
||||
);
|
||||
$parameters = array_merge($defaults, $post);
|
||||
|
||||
\OC_Util::addScript( '3rdparty', 'strengthify/jquery.strengthify' );
|
||||
\OC_Util::addStyle( '3rdparty', 'strengthify/strengthify' );
|
||||
\OC_Util::addScript('setup');
|
||||
\OC_Template::printGuestPage('', 'installation', $parameters);
|
||||
}
|
||||
|
||||
public function finishSetup() {
|
||||
header( 'Location: '.\OC_Helper::linkToRoute( 'post_setup_check' ));
|
||||
exit();
|
||||
}
|
||||
|
||||
public function loadAutoConfig($post) {
|
||||
$autosetup_file = \OC::$SERVERROOT.'/config/autoconfig.php';
|
||||
if( file_exists( $autosetup_file )) {
|
||||
\OC_Log::write('core', 'Autoconfig file found, setting up owncloud...', \OC_Log::INFO);
|
||||
$AUTOCONFIG = array();
|
||||
include $autosetup_file;
|
||||
$post = array_merge ($post, $AUTOCONFIG);
|
||||
}
|
||||
|
||||
$dbIsSet = isset($post['dbtype']);
|
||||
$directoryIsSet = isset($post['directory']);
|
||||
$adminAccountIsSet = isset($post['adminlogin']);
|
||||
|
||||
if ($dbIsSet AND $directoryIsSet AND $adminAccountIsSet) {
|
||||
$post['install'] = 'true';
|
||||
if( file_exists( $autosetup_file )) {
|
||||
unlink($autosetup_file);
|
||||
}
|
||||
}
|
||||
$post['dbIsSet'] = $dbIsSet;
|
||||
$post['directoryIsSet'] = $directoryIsSet;
|
||||
|
||||
return $post;
|
||||
}
|
||||
|
||||
public function getSystemInfo() {
|
||||
$hasSQLite = class_exists('SQLite3');
|
||||
$hasMySQL = is_callable('mysql_connect');
|
||||
$hasPostgreSQL = is_callable('pg_connect');
|
||||
$hasOracle = is_callable('oci_connect');
|
||||
$hasMSSQL = is_callable('sqlsrv_connect');
|
||||
$databases = array();
|
||||
if ($hasSQLite) {
|
||||
$databases['sqlite'] = 'SQLite';
|
||||
}
|
||||
if ($hasMySQL) {
|
||||
$databases['mysql'] = 'MySQL';
|
||||
}
|
||||
if ($hasPostgreSQL) {
|
||||
$databases['pgsql'] = 'PostgreSQL';
|
||||
}
|
||||
if ($hasOracle) {
|
||||
$databases['oci'] = 'Oracle';
|
||||
}
|
||||
if ($hasMSSQL) {
|
||||
$databases['mssql'] = 'MS SQL';
|
||||
}
|
||||
$datadir = \OC_Config::getValue('datadirectory', \OC::$SERVERROOT.'/data');
|
||||
$vulnerableToNullByte = false;
|
||||
if(@file_exists(__FILE__."\0Nullbyte")) { // Check if the used PHP version is vulnerable to the NULL Byte attack (CVE-2006-7243)
|
||||
$vulnerableToNullByte = true;
|
||||
}
|
||||
|
||||
$errors = array();
|
||||
|
||||
// Protect data directory here, so we can test if the protection is working
|
||||
\OC_Setup::protectDataDirectory();
|
||||
try {
|
||||
$htaccessWorking = \OC_Util::isHtAccessWorking();
|
||||
} catch (\OC\HintException $e) {
|
||||
$errors[] = array(
|
||||
'error' => $e->getMessage(),
|
||||
'hint' => $e->getHint()
|
||||
);
|
||||
$htaccessWorking = false;
|
||||
}
|
||||
|
||||
return array(
|
||||
'hasSQLite' => $hasSQLite,
|
||||
'hasMySQL' => $hasMySQL,
|
||||
'hasPostgreSQL' => $hasPostgreSQL,
|
||||
'hasOracle' => $hasOracle,
|
||||
'hasMSSQL' => $hasMSSQL,
|
||||
'databases' => $databases,
|
||||
'directory' => $datadir,
|
||||
'secureRNG' => \OC_Util::secureRNGAvailable(),
|
||||
'htaccessWorking' => $htaccessWorking,
|
||||
'vulnerableToNullByte' => $vulnerableToNullByte,
|
||||
'errors' => $errors,
|
||||
);
|
||||
}
|
||||
}
|
|
@ -48,13 +48,13 @@
|
|||
<legend><?php print_unescaped($l->t( 'Create an <strong>admin account</strong>' )); ?></legend>
|
||||
<p class="infield grouptop">
|
||||
<input type="text" name="adminlogin" id="adminlogin" placeholder=""
|
||||
value="<?php p(OC_Helper::init_var('adminlogin')); ?>" autocomplete="off" autofocus required />
|
||||
value="<?php p($_['adminlogin']); ?>" autocomplete="off" autofocus required />
|
||||
<label for="adminlogin" class="infield"><?php p($l->t( 'Username' )); ?></label>
|
||||
<img class="svg" src="<?php p(image_path('', 'actions/user.svg')); ?>" alt="" />
|
||||
</p>
|
||||
<p class="infield groupbottom">
|
||||
<input type="password" name="adminpass" data-typetoggle="#show" id="adminpass" placeholder=""
|
||||
value="<?php p(OC_Helper::init_var('adminpass')); ?>" required />
|
||||
value="<?php p($_['adminpass']); ?>" required />
|
||||
<label for="adminpass" class="infield"><?php p($l->t( 'Password' )); ?></label>
|
||||
<img class="svg" id="adminpass-icon" src="<?php print_unescaped(image_path('', 'actions/password.svg')); ?>" alt="" />
|
||||
<input type="checkbox" id="show" name="show" />
|
||||
|
@ -75,7 +75,7 @@
|
|||
<label for="directory"><?php p($l->t( 'Data folder' )); ?></label>
|
||||
<input type="text" name="directory" id="directory"
|
||||
placeholder="<?php p(OC::$SERVERROOT."/data"); ?>"
|
||||
value="<?php p(OC_Helper::init_var('directory', $_['directory'])); ?>" />
|
||||
value="<?php p($_['directory']); ?>" />
|
||||
</div>
|
||||
</fieldset>
|
||||
<?php endif; ?>
|
||||
|
@ -86,62 +86,16 @@
|
|||
$hasOtherDB = true; else $hasOtherDB =false; //other than SQLite ?>
|
||||
<legend><?php p($l->t( 'Configure the database' )); ?></legend>
|
||||
<div id="selectDbType">
|
||||
<?php if($_['hasSQLite']): ?>
|
||||
<input type='hidden' id='hasSQLite' value="true" />
|
||||
<?php if(!$hasOtherDB): ?>
|
||||
<p>SQLite <?php p($l->t( 'will be used' )); ?>.</p>
|
||||
<input type="hidden" id="dbtype" name="dbtype" value="sqlite" />
|
||||
<?php foreach($_['databases'] as $type => $label): ?>
|
||||
<?php if(count($_['databases']) === 1): ?>
|
||||
<p class="info"><?php p($label . ' ' . $l->t( 'will be used' )); ?>.</p>
|
||||
<input type="hidden" id="dbtype" name="dbtype" value="<?php p($type) ?>" />
|
||||
<?php else: ?>
|
||||
<input type="radio" name="dbtype" value="sqlite" id="sqlite"
|
||||
<?php OC_Helper::init_radio('dbtype', 'sqlite', 'sqlite'); ?>/>
|
||||
<label class="sqlite" for="sqlite">SQLite</label>
|
||||
<?php endif; ?>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if($_['hasMySQL']): ?>
|
||||
<input type='hidden' id='hasMySQL' value='true'/>
|
||||
<?php if(!$_['hasSQLite'] and !$_['hasPostgreSQL'] and !$_['hasOracle'] and !$_['hasMSSQL']): ?>
|
||||
<p>MySQL <?php p($l->t( 'will be used' )); ?>.</p>
|
||||
<input type="hidden" id="dbtype" name="dbtype" value="mysql" />
|
||||
<?php else: ?>
|
||||
<input type="radio" name="dbtype" value="mysql" id="mysql"
|
||||
<?php OC_Helper::init_radio('dbtype', 'mysql', 'sqlite'); ?>/>
|
||||
<label class="mysql" for="mysql">MySQL</label>
|
||||
<?php endif; ?>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if($_['hasPostgreSQL']): ?>
|
||||
<?php if(!$_['hasSQLite'] and !$_['hasMySQL'] and !$_['hasOracle'] and !$_['hasMSSQL']): ?>
|
||||
<p>PostgreSQL <?php p($l->t( 'will be used' )); ?>.</p>
|
||||
<input type="hidden" id="dbtype" name="dbtype" value="pgsql" />
|
||||
<?php else: ?>
|
||||
<label class="pgsql" for="pgsql">PostgreSQL</label>
|
||||
<input type="radio" name="dbtype" value='pgsql' id="pgsql"
|
||||
<?php OC_Helper::init_radio('dbtype', 'pgsql', 'sqlite'); ?>/>
|
||||
<?php endif; ?>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if($_['hasOracle']): ?>
|
||||
<?php if(!$_['hasSQLite'] and !$_['hasMySQL'] and !$_['hasPostgreSQL'] and !$_['hasMSSQL']): ?>
|
||||
<p>Oracle <?php p($l->t( 'will be used' )); ?>.</p>
|
||||
<input type="hidden" id="dbtype" name="dbtype" value="oci" />
|
||||
<?php else: ?>
|
||||
<label class="oci" for="oci">Oracle</label>
|
||||
<input type="radio" name="dbtype" value='oci' id="oci"
|
||||
<?php OC_Helper::init_radio('dbtype', 'oci', 'sqlite'); ?>/>
|
||||
<?php endif; ?>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if($_['hasMSSQL']): ?>
|
||||
<input type='hidden' id='hasMSSQL' value='true'/>
|
||||
<?php if(!$_['hasSQLite'] and !$_['hasMySQL'] and !$_['hasPostgreSQL'] and !$_['hasOracle']): ?>
|
||||
<p>MS SQL <?php p($l->t( 'will be used' )); ?>.</p>
|
||||
<input type="hidden" id="dbtype" name="dbtype" value="mssql" />
|
||||
<?php else: ?>
|
||||
<label class="mssql" for="mssql">MS SQL</label>
|
||||
<input type="radio" name="dbtype" value='mssql' id="mssql" <?php OC_Helper::init_radio('dbtype', 'mssql', 'sqlite'); ?>/>
|
||||
<?php endif; ?>
|
||||
<input type="radio" name="dbtype" value="<?php p($type) ?>" id="<?php p($type) ?>"
|
||||
<?php p($_['dbtype'] === $type ? 'checked="checked" ' : '') ?>/>
|
||||
<label class="<?php p($type) ?>" for="<?php p($type) ?>"><?php p($label) ?></label>
|
||||
<?php endif; ?>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
|
||||
<?php if($hasOtherDB): ?>
|
||||
|
@ -149,11 +103,11 @@
|
|||
<p class="infield grouptop">
|
||||
<label for="dbuser" class="infield"><?php p($l->t( 'Database user' )); ?></label>
|
||||
<input type="text" name="dbuser" id="dbuser" placeholder=""
|
||||
value="<?php p(OC_Helper::init_var('dbuser')); ?>" autocomplete="off" />
|
||||
value="<?php p($_['dbuser']); ?>" autocomplete="off" />
|
||||
</p>
|
||||
<p class="infield groupmiddle">
|
||||
<input type="password" name="dbpass" id="dbpass" placeholder="" data-typetoggle="#dbpassword"
|
||||
value="<?php p(OC_Helper::init_var('dbpass')); ?>" />
|
||||
value="<?php p($_['dbpass']); ?>" />
|
||||
<label for="dbpass" class="infield"><?php p($l->t( 'Database password' )); ?></label>
|
||||
<input type="checkbox" id="dbpassword" name="dbpassword" />
|
||||
<label for="dbpassword"></label>
|
||||
|
@ -161,7 +115,7 @@
|
|||
<p class="infield groupmiddle">
|
||||
<label for="dbname" class="infield"><?php p($l->t( 'Database name' )); ?></label>
|
||||
<input type="text" name="dbname" id="dbname" placeholder=""
|
||||
value="<?php p(OC_Helper::init_var('dbname')); ?>"
|
||||
value="<?php p($_['dbname']); ?>"
|
||||
autocomplete="off" pattern="[0-9a-zA-Z$_-]+" />
|
||||
</p>
|
||||
<?php if($_['hasOracle']): ?>
|
||||
|
@ -169,14 +123,14 @@
|
|||
<p class="infield groupmiddle">
|
||||
<label for="dbtablespace" class="infield"><?php p($l->t( 'Database tablespace' )); ?></label>
|
||||
<input type="text" name="dbtablespace" id="dbtablespace" placeholder=""
|
||||
value="<?php p(OC_Helper::init_var('dbtablespace')); ?>" autocomplete="off" />
|
||||
value="<?php p($_['dbtablespace']); ?>" autocomplete="off" />
|
||||
</p>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<p class="infield groupbottom">
|
||||
<label for="dbhost" class="infield"><?php p($l->t( 'Database host' )); ?></label>
|
||||
<input type="text" name="dbhost" id="dbhost" placeholder=""
|
||||
value="<?php p(OC_Helper::init_var('dbhost')); ?>" />
|
||||
value="<?php p($_['dbhost']); ?>" />
|
||||
</p>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
<?php p($theme->getTitle()); ?>
|
||||
</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="viewport" content="width=device-width, minimum-scale=1.0, maximum-scale=1.0">
|
||||
<link rel="shortcut icon" href="<?php print_unescaped(image_path('', 'favicon.png')); ?>" />
|
||||
<link rel="apple-touch-icon-precomposed" href="<?php print_unescaped(image_path('', 'favicon-touch.png')); ?>" />
|
||||
<?php foreach ($_['cssfiles'] as $cssfile): ?>
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
<?php p($theme->getTitle()); ?>
|
||||
</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="viewport" content="width=device-width, minimum-scale=1.0, maximum-scale=1.0">
|
||||
<meta name="apple-itunes-app" content="app-id=543672169">
|
||||
<link rel="shortcut icon" href="<?php print_unescaped(image_path('', 'favicon.png')); ?>" />
|
||||
<link rel="apple-touch-icon-precomposed" href="<?php print_unescaped(image_path('', 'favicon-touch.png')); ?>" />
|
||||
|
|
|
@ -48,15 +48,16 @@
|
|||
<a href="<?php print_unescaped(link_to('', 'index.php')); ?>" title="" id="owncloud"><img class="svg"
|
||||
src="<?php print_unescaped(image_path('', 'logo-wide.svg')); ?>" alt="<?php p($theme->getName()); ?>" /></a>
|
||||
<div id="logo-claim" style="display:none;"><?php p($theme->getLogoClaim()); ?></div>
|
||||
<ul id="settings" class="svg">
|
||||
<div id="settings" class="svg">
|
||||
<span id="expand" tabindex="0" role="link">
|
||||
<span id="expandDisplayName"><?php p(trim($_['user_displayname']) != '' ? $_['user_displayname'] : $_['user_uid']) ?></span>
|
||||
<img class="svg" src="<?php print_unescaped(image_path('', 'actions/caret.svg')); ?>" />
|
||||
<?php if ($_['enableAvatars']): ?>
|
||||
<div class="avatardiv"></div>
|
||||
<?php endif; ?>
|
||||
<img class="svg" alt="" src="<?php print_unescaped(image_path('', 'actions/caret.svg')); ?>" />
|
||||
</span>
|
||||
<?php if ($_['enableAvatars']): ?>
|
||||
<div class="avatardiv"></div>
|
||||
<?php endif; ?>
|
||||
<div id="expanddiv">
|
||||
<ul>
|
||||
<?php foreach($_['settingsnavigation'] as $entry):?>
|
||||
<li>
|
||||
<a href="<?php print_unescaped($entry['href']); ?>" title=""
|
||||
|
@ -72,8 +73,9 @@
|
|||
<?php p($l->t('Log out'));?>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<form class="searchbox" action="#" method="post">
|
||||
<input id="searchbox" class="svg" type="search" name="query"
|
||||
|
@ -83,37 +85,40 @@
|
|||
</div></header>
|
||||
|
||||
<nav><div id="navigation">
|
||||
<ul id="apps" class="svg">
|
||||
<div class="wrapper"><!-- for sticky footer of apps management -->
|
||||
<div id="apps" class="svg">
|
||||
<ul class="wrapper"><!-- for sticky footer of apps management -->
|
||||
<?php foreach($_['navigation'] as $entry): ?>
|
||||
<li data-id="<?php p($entry['id']); ?>">
|
||||
<a href="<?php print_unescaped($entry['href']); ?>" title=""
|
||||
<?php if( $entry['active'] ): ?> class="active"<?php endif; ?>>
|
||||
<img class="icon svg" src="<?php print_unescaped($entry['icon']); ?>"/>
|
||||
<img class="icon svg" alt="" src="<?php print_unescaped($entry['icon']); ?>"/>
|
||||
<span>
|
||||
<?php p($entry['name']); ?>
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
<?php endforeach; ?>
|
||||
|
||||
<?php if(OC_User::isAdminUser(OC_User::getUser())): ?>
|
||||
<div class="push"></div><!-- for for sticky footer of apps management -->
|
||||
<li class="push"></li><!-- for sticky footer of apps management -->
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</ul>
|
||||
|
||||
<!-- show "More apps" link to app administration directly in app navigation, as sticky footer -->
|
||||
<?php if(OC_User::isAdminUser(OC_User::getUser())): ?>
|
||||
<li id="apps-management">
|
||||
<ul id="apps-management">
|
||||
<li>
|
||||
<a href="<?php print_unescaped(OC_Helper::linkToRoute('settings_apps').'?installed'); ?>" title=""
|
||||
<?php if( $_['appsmanagement_active'] ): ?> class="active"<?php endif; ?>>
|
||||
<img class="icon svg" src="<?php print_unescaped(OC_Helper::imagePath('settings', 'apps.svg')); ?>"/>
|
||||
<img class="icon svg" alt="" src="<?php print_unescaped(OC_Helper::imagePath('settings', 'apps.svg')); ?>"/>
|
||||
<span>
|
||||
<?php p($l->t('Apps')); ?>
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<?php endif; ?>
|
||||
</ul>
|
||||
</div>
|
||||
</div></nav>
|
||||
|
||||
<div id="content-wrapper">
|
||||
|
|
|
@ -504,11 +504,12 @@ class OC {
|
|||
|
||||
if (!defined('PHPUNIT_RUN')) {
|
||||
if (defined('DEBUG') and DEBUG) {
|
||||
OC\Log\ErrorHandler::register(true);
|
||||
set_exception_handler(array('OC_Template', 'printExceptionErrorPage'));
|
||||
} else {
|
||||
OC\Log\ErrorHandler::register();
|
||||
OC\Log\ErrorHandler::setLogger(OC_Log::$object);
|
||||
}
|
||||
OC\Log\ErrorHandler::setLogger(OC_Log::$object);
|
||||
}
|
||||
|
||||
// register the stream wrappers
|
||||
|
@ -690,7 +691,8 @@ class OC {
|
|||
|
||||
// Check if ownCloud is installed or in maintenance (update) mode
|
||||
if (!OC_Config::getValue('installed', false)) {
|
||||
require_once 'core/setup.php';
|
||||
$controller = new OC\Core\Setup\Controller();
|
||||
$controller->run($_POST);
|
||||
exit();
|
||||
}
|
||||
|
||||
|
|
|
@ -63,8 +63,8 @@ class OC_App{
|
|||
ob_start();
|
||||
foreach( $apps as $app ) {
|
||||
if((is_null($types) or self::isType($app, $types)) && !in_array($app, self::$loadedApps)) {
|
||||
self::loadApp($app);
|
||||
self::$loadedApps[] = $app;
|
||||
self::loadApp($app);
|
||||
}
|
||||
}
|
||||
ob_end_clean();
|
||||
|
|
50
lib/private/connector/sabre/exceptionloggerplugin.php
Normal file
|
@ -0,0 +1,50 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* ownCloud
|
||||
*
|
||||
* @author Vincent Petry
|
||||
* @copyright 2014 Vincent Petry <pvince81@owncloud.com>
|
||||
*
|
||||
* @license AGPL3
|
||||
*/
|
||||
|
||||
class OC_Connector_Sabre_ExceptionLoggerPlugin extends Sabre_DAV_ServerPlugin
|
||||
{
|
||||
private $appName;
|
||||
|
||||
/**
|
||||
* @param string $loggerAppName app name to use when logging
|
||||
*/
|
||||
public function __construct($loggerAppName = 'webdav') {
|
||||
$this->appName = $loggerAppName;
|
||||
}
|
||||
|
||||
/**
|
||||
* This initializes the plugin.
|
||||
*
|
||||
* This function is called by Sabre_DAV_Server, after
|
||||
* addPlugin is called.
|
||||
*
|
||||
* This method should set up the required event subscriptions.
|
||||
*
|
||||
* @param Sabre_DAV_Server $server
|
||||
* @return void
|
||||
*/
|
||||
public function initialize(Sabre_DAV_Server $server) {
|
||||
|
||||
$server->subscribeEvent('exception', array($this, 'logException'), 10);
|
||||
}
|
||||
|
||||
/**
|
||||
* Log exception
|
||||
*
|
||||
* @internal param Exception $e exception
|
||||
*/
|
||||
public function logException($e) {
|
||||
$exceptionClass = get_class($e);
|
||||
if ($exceptionClass !== 'Sabre_DAV_Exception_NotAuthenticated') {
|
||||
\OCP\Util::logException($this->appName, $e);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -79,7 +79,7 @@ class OC_Connector_Sabre_File extends OC_Connector_Sabre_Node implements Sabre_D
|
|||
\OC_Log::write('webdav', '\OC\Files\Filesystem::file_put_contents() failed', \OC_Log::ERROR);
|
||||
$fs->unlink($partpath);
|
||||
// because we have no clue about the cause we can only throw back a 500/Internal Server Error
|
||||
throw new Sabre_DAV_Exception();
|
||||
throw new Sabre_DAV_Exception('Could not write file contents');
|
||||
}
|
||||
} catch (\OCP\Files\NotPermittedException $e) {
|
||||
// a more general case - due to whatever reason the content could not be written
|
||||
|
@ -105,7 +105,7 @@ class OC_Connector_Sabre_File extends OC_Connector_Sabre_Node implements Sabre_D
|
|||
if ($renameOkay === false || $fileExists === false) {
|
||||
\OC_Log::write('webdav', '\OC\Files\Filesystem::rename() failed', \OC_Log::ERROR);
|
||||
$fs->unlink($partpath);
|
||||
throw new Sabre_DAV_Exception();
|
||||
throw new Sabre_DAV_Exception('Could not rename part file to final file');
|
||||
}
|
||||
|
||||
// allow sync clients to send the mtime along in a header
|
||||
|
@ -246,7 +246,7 @@ class OC_Connector_Sabre_File extends OC_Connector_Sabre_Node implements Sabre_D
|
|||
if ($fileExists) {
|
||||
$fs->unlink($targetPath);
|
||||
}
|
||||
throw new Sabre_DAV_Exception();
|
||||
throw new Sabre_DAV_Exception('Could not rename part file assembled from chunks');
|
||||
}
|
||||
|
||||
// allow sync clients to send the mtime along in a header
|
||||
|
|
|
@ -38,7 +38,20 @@ class ObjectTree extends \Sabre_DAV_ObjectTree {
|
|||
return $this->rootNode;
|
||||
}
|
||||
|
||||
$info = $this->getFileView()->getFileInfo($path);
|
||||
if (pathinfo($path, PATHINFO_EXTENSION) === 'part') {
|
||||
// read from storage
|
||||
$absPath = $this->getFileView()->getAbsolutePath($path);
|
||||
list($storage, $internalPath) = Filesystem::resolvePath('/' . $absPath);
|
||||
if ($storage) {
|
||||
$scanner = $storage->getScanner($internalPath);
|
||||
// get data directly
|
||||
$info = $scanner->getData($internalPath);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// read from cache
|
||||
$info = $this->getFileView()->getFileInfo($path);
|
||||
}
|
||||
|
||||
if (!$info) {
|
||||
throw new \Sabre_DAV_Exception_NotFound('File with name ' . $path . ' could not be located');
|
||||
|
|
|
@ -161,6 +161,7 @@ class OC_Helper {
|
|||
'application/vnd.oasis.opendocument.text-template' => 'x-office/document',
|
||||
'application/vnd.oasis.opendocument.text-web' => 'x-office/document',
|
||||
'application/vnd.oasis.opendocument.text-master' => 'x-office/document',
|
||||
'application/mspowerpoint' => 'x-office/presentation',
|
||||
'application/vnd.ms-powerpoint' => 'x-office/presentation',
|
||||
'application/vnd.openxmlformats-officedocument.presentationml.presentation' => 'x-office/presentation',
|
||||
'application/vnd.openxmlformats-officedocument.presentationml.template' => 'x-office/presentation',
|
||||
|
@ -171,6 +172,7 @@ class OC_Helper {
|
|||
'application/vnd.ms-powerpoint.slideshow.macroEnabled.12' => 'x-office/presentation',
|
||||
'application/vnd.oasis.opendocument.presentation' => 'x-office/presentation',
|
||||
'application/vnd.oasis.opendocument.presentation-template' => 'x-office/presentation',
|
||||
'application/msexcel' => 'x-office/spreadsheet',
|
||||
'application/vnd.ms-excel' => 'x-office/spreadsheet',
|
||||
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' => 'x-office/spreadsheet',
|
||||
'application/vnd.openxmlformats-officedocument.spreadsheetml.template' => 'x-office/spreadsheet',
|
||||
|
@ -180,6 +182,7 @@ class OC_Helper {
|
|||
'application/vnd.ms-excel.sheet.binary.macroEnabled.12' => 'x-office/spreadsheet',
|
||||
'application/vnd.oasis.opendocument.spreadsheet' => 'x-office/spreadsheet',
|
||||
'application/vnd.oasis.opendocument.spreadsheet-template' => 'x-office/spreadsheet',
|
||||
'application/msaccess' => 'database',
|
||||
);
|
||||
|
||||
if (isset($alias[$mimetype])) {
|
||||
|
@ -445,29 +448,6 @@ class OC_Helper {
|
|||
*
|
||||
*/
|
||||
|
||||
//FIXME: should also check for value validation (i.e. the email is an email).
|
||||
public static function init_var($s, $d = "") {
|
||||
$r = $d;
|
||||
if (isset($_REQUEST[$s]) && !empty($_REQUEST[$s])) {
|
||||
$r = OC_Util::sanitizeHTML($_REQUEST[$s]);
|
||||
}
|
||||
|
||||
return $r;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns "checked"-attribute if request contains selected radio element
|
||||
* OR if radio element is the default one -- maybe?
|
||||
*
|
||||
* @param string $s Name of radio-button element name
|
||||
* @param string $v Value of current radio-button element
|
||||
* @param string $d Value of default radio-button element
|
||||
*/
|
||||
public static function init_radio($s, $v, $d) {
|
||||
if ((isset($_REQUEST[$s]) && $_REQUEST[$s] == $v) || (!isset($_REQUEST[$s]) && $v == $d))
|
||||
print "checked=\"checked\" ";
|
||||
}
|
||||
|
||||
/**
|
||||
* detect if a given program is found in the search PATH
|
||||
*
|
||||
|
@ -828,23 +808,39 @@ class OC_Helper {
|
|||
* @return number of bytes representing
|
||||
*/
|
||||
public static function maxUploadFilesize($dir) {
|
||||
$upload_max_filesize = OCP\Util::computerFileSize(ini_get('upload_max_filesize'));
|
||||
$post_max_size = OCP\Util::computerFileSize(ini_get('post_max_size'));
|
||||
$freeSpace = \OC\Files\Filesystem::free_space($dir);
|
||||
if ((int)$upload_max_filesize === 0 and (int)$post_max_size === 0) {
|
||||
$maxUploadFilesize = \OC\Files\SPACE_UNLIMITED;
|
||||
} elseif ((int)$upload_max_filesize === 0 or (int)$post_max_size === 0) {
|
||||
$maxUploadFilesize = max($upload_max_filesize, $post_max_size); //only the non 0 value counts
|
||||
} else {
|
||||
$maxUploadFilesize = min($upload_max_filesize, $post_max_size);
|
||||
}
|
||||
return min(self::freeSpace($dir), self::uploadLimit());
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate free space left within user quota
|
||||
*
|
||||
* @param $dir the current folder where the user currently operates
|
||||
* @return number of bytes representing
|
||||
*/
|
||||
public static function freeSpace($dir) {
|
||||
$freeSpace = \OC\Files\Filesystem::free_space($dir);
|
||||
if ($freeSpace !== \OC\Files\SPACE_UNKNOWN) {
|
||||
$freeSpace = max($freeSpace, 0);
|
||||
|
||||
return min($maxUploadFilesize, $freeSpace);
|
||||
return $freeSpace;
|
||||
} else {
|
||||
return $maxUploadFilesize;
|
||||
return INF;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate PHP upload limit
|
||||
*
|
||||
* @return PHP upload file size limit
|
||||
*/
|
||||
public static function uploadLimit() {
|
||||
$upload_max_filesize = OCP\Util::computerFileSize(ini_get('upload_max_filesize'));
|
||||
$post_max_size = OCP\Util::computerFileSize(ini_get('post_max_size'));
|
||||
if ((int)$upload_max_filesize === 0 and (int)$post_max_size === 0) {
|
||||
return INF;
|
||||
} elseif ((int)$upload_max_filesize === 0 or (int)$post_max_size === 0) {
|
||||
return max($upload_max_filesize, $post_max_size); //only the non 0 value counts
|
||||
} else {
|
||||
return min($upload_max_filesize, $post_max_size);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -409,14 +409,14 @@ class OC_Image {
|
|||
|
||||
/**
|
||||
* @brief Loads an image from a local file.
|
||||
* @param $imageref The path to a local file.
|
||||
* @param $imagePath The path to a local file.
|
||||
* @returns An image resource or false on error
|
||||
*/
|
||||
public function loadFromFile($imagePath=false) {
|
||||
// exif_imagetype throws "read error!" if file is less than 12 byte
|
||||
if(!@is_file($imagePath) || !file_exists($imagePath) || filesize($imagePath) < 12 || !is_readable($imagePath)) {
|
||||
// Debug output disabled because this method is tried before loadFromBase64?
|
||||
OC_Log::write('core', 'OC_Image->loadFromFile, couldn\'t load: '.$imagePath, OC_Log::DEBUG);
|
||||
OC_Log::write('core', 'OC_Image->loadFromFile, couldn\'t load: ' . (string) urlencode($imagePath), OC_Log::DEBUG);
|
||||
return false;
|
||||
}
|
||||
$iType = exif_imagetype($imagePath);
|
||||
|
|
|
@ -132,10 +132,10 @@ class OC_L10N implements \OCP\IL10N {
|
|||
$i18ndir = self::findI18nDir($app);
|
||||
// Localization is in /l10n, Texts are in $i18ndir
|
||||
// (Just no need to define date/time format etc. twice)
|
||||
if((OC_Helper::issubdirectory($i18ndir.$lang.'.php', OC_App::getAppPath($app).'/l10n/')
|
||||
|| OC_Helper::issubdirectory($i18ndir.$lang.'.php', OC::$SERVERROOT.'/core/l10n/')
|
||||
if((OC_Helper::issubdirectory($i18ndir.$lang.'.php', OC::$SERVERROOT.'/core/l10n/')
|
||||
|| OC_Helper::issubdirectory($i18ndir.$lang.'.php', OC::$SERVERROOT.'/lib/l10n/')
|
||||
|| OC_Helper::issubdirectory($i18ndir.$lang.'.php', OC::$SERVERROOT.'/settings')
|
||||
|| OC_Helper::issubdirectory($i18ndir.$lang.'.php', OC_App::getAppPath($app).'/l10n/')
|
||||
)
|
||||
&& file_exists($i18ndir.$lang.'.php')) {
|
||||
// Include the file, save the data from $CONFIG
|
||||
|
|
|
@ -14,10 +14,23 @@ class ErrorHandler {
|
|||
/** @var LoggerInterface */
|
||||
private static $logger;
|
||||
|
||||
public static function register() {
|
||||
/**
|
||||
* @brief remove password in URLs
|
||||
* @param string $msg
|
||||
* @return string
|
||||
*/
|
||||
protected static function removePassword($msg) {
|
||||
return preg_replace('/\/\/(.*):(.*)@/', '//xxx:xxx@', $msg);
|
||||
}
|
||||
|
||||
public static function register($debug=false) {
|
||||
$handler = new ErrorHandler();
|
||||
|
||||
set_error_handler(array($handler, 'onError'));
|
||||
if ($debug) {
|
||||
set_error_handler(array($handler, 'onAll'), E_ALL);
|
||||
} else {
|
||||
set_error_handler(array($handler, 'onError'));
|
||||
}
|
||||
register_shutdown_function(array($handler, 'onShutdown'));
|
||||
set_exception_handler(array($handler, 'onException'));
|
||||
}
|
||||
|
@ -32,14 +45,14 @@ class ErrorHandler {
|
|||
if($error && self::$logger) {
|
||||
//ob_end_clean();
|
||||
$msg = $error['message'] . ' at ' . $error['file'] . '#' . $error['line'];
|
||||
self::$logger->critical($msg, array('app' => 'PHP'));
|
||||
self::$logger->critical(self::removePassword($msg), array('app' => 'PHP'));
|
||||
}
|
||||
}
|
||||
|
||||
// Uncaught exception handler
|
||||
public static function onException($exception) {
|
||||
$msg = $exception->getMessage() . ' at ' . $exception->getFile() . '#' . $exception->getLine();
|
||||
self::$logger->critical($msg, array('app' => 'PHP'));
|
||||
self::$logger->critical(self::removePassword($msg), array('app' => 'PHP'));
|
||||
}
|
||||
|
||||
//Recoverable errors handler
|
||||
|
@ -48,7 +61,15 @@ class ErrorHandler {
|
|||
return;
|
||||
}
|
||||
$msg = $message . ' at ' . $file . '#' . $line;
|
||||
self::$logger->warning($msg, array('app' => 'PHP'));
|
||||
self::$logger->error(self::removePassword($msg), array('app' => 'PHP'));
|
||||
|
||||
}
|
||||
|
||||
//Recoverable handler which catch all errors, warnings and notices
|
||||
public static function onAll($number, $message, $file, $line) {
|
||||
$msg = $message . ' at ' . $file . '#' . $line;
|
||||
self::$logger->debug(self::removePassword($msg), array('app' => 'PHP'));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -69,7 +69,6 @@ class OC_Log_Owncloud {
|
|||
}
|
||||
$time = new DateTime(null, $timezone);
|
||||
// remove username/passswords from URLs before writing the to the log file
|
||||
$message = preg_replace('/\/\/(.*):(.*)@/', '//xxx:xxx@', $message);
|
||||
$entry=array('app'=>$app, 'message'=>$message, 'level'=>$level, 'time'=> $time->format($format));
|
||||
$entry = json_encode($entry);
|
||||
$handle = @fopen(self::$logFile, 'a');
|
||||
|
|
|
@ -9,15 +9,8 @@
|
|||
namespace OC\Memcache;
|
||||
|
||||
class APC extends Cache {
|
||||
/**
|
||||
* entries in APC gets namespaced to prevent collisions between owncloud instances and users
|
||||
*/
|
||||
protected function getNameSpace() {
|
||||
return $this->prefix;
|
||||
}
|
||||
|
||||
public function get($key) {
|
||||
$result = apc_fetch($this->getNamespace() . $key, $success);
|
||||
$result = apc_fetch($this->getPrefix() . $key, $success);
|
||||
if (!$success) {
|
||||
return null;
|
||||
}
|
||||
|
@ -25,26 +18,22 @@ class APC extends Cache {
|
|||
}
|
||||
|
||||
public function set($key, $value, $ttl = 0) {
|
||||
return apc_store($this->getNamespace() . $key, $value, $ttl);
|
||||
return apc_store($this->getPrefix() . $key, $value, $ttl);
|
||||
}
|
||||
|
||||
public function hasKey($key) {
|
||||
return apc_exists($this->getNamespace() . $key);
|
||||
return apc_exists($this->getPrefix() . $key);
|
||||
}
|
||||
|
||||
public function remove($key) {
|
||||
return apc_delete($this->getNamespace() . $key);
|
||||
return apc_delete($this->getPrefix() . $key);
|
||||
}
|
||||
|
||||
public function clear($prefix = '') {
|
||||
$ns = $this->getNamespace() . $prefix;
|
||||
$cache = apc_cache_info('user');
|
||||
foreach ($cache['cache_list'] as $entry) {
|
||||
if (strpos($entry['info'], $ns) === 0) {
|
||||
apc_delete($entry['info']);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
$ns = $this->getPrefix() . $prefix;
|
||||
$ns = preg_quote($ns, '/');
|
||||
$iter = new \APCIterator('user', '/^' . $ns . '/');
|
||||
return apc_delete($iter);
|
||||
}
|
||||
|
||||
static public function isAvailable() {
|
||||
|
|
|
@ -9,13 +9,6 @@
|
|||
namespace OC\Memcache;
|
||||
|
||||
class APCu extends APC {
|
||||
public function clear($prefix = '') {
|
||||
$ns = $this->getNamespace() . $prefix;
|
||||
$ns = preg_quote($ns, '/');
|
||||
$iter = new \APCIterator('user', '/^'.$ns.'/');
|
||||
return apc_delete($iter);
|
||||
}
|
||||
|
||||
static public function isAvailable() {
|
||||
if (!extension_loaded('apcu')) {
|
||||
return false;
|
||||
|
|
|
@ -18,7 +18,7 @@ abstract class Cache implements \ArrayAccess {
|
|||
* @param string $prefix
|
||||
*/
|
||||
public function __construct($prefix = '') {
|
||||
$this->prefix = \OC_Util::getInstanceId() . '/' . $prefix;
|
||||
$this->prefix = $prefix;
|
||||
}
|
||||
|
||||
public function getPrefix() {
|
||||
|
|
|
@ -8,7 +8,21 @@
|
|||
|
||||
namespace OC\Memcache;
|
||||
|
||||
class Factory {
|
||||
use \OCP\ICacheFactory;
|
||||
|
||||
class Factory implements ICacheFactory {
|
||||
/**
|
||||
* @var string $globalPrefix
|
||||
*/
|
||||
private $globalPrefix;
|
||||
|
||||
/**
|
||||
* @param string $globalPrefix
|
||||
*/
|
||||
public function __construct($globalPrefix) {
|
||||
$this->globalPrefix = $globalPrefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* get a cache instance, will return null if no backend is available
|
||||
*
|
||||
|
@ -16,6 +30,7 @@ class Factory {
|
|||
* @return \OC\Memcache\Cache
|
||||
*/
|
||||
function create($prefix = '') {
|
||||
$prefix = $this->globalPrefix . '/' . $prefix;
|
||||
if (XCache::isAvailable()) {
|
||||
return new XCache($prefix);
|
||||
} elseif (APCu::isAvailable()) {
|
||||
|
|
|
@ -21,93 +21,91 @@
|
|||
*/
|
||||
|
||||
/**
|
||||
* list of mimetypes by extension
|
||||
* Array mapping file extensions to mimetypes (in alphabetical order).
|
||||
*/
|
||||
|
||||
return array(
|
||||
'accdb'=>'application/msaccess',
|
||||
'ai' => 'application/illustrator',
|
||||
'avi'=>'video/x-msvideo',
|
||||
'bash' => 'text/x-shellscript',
|
||||
'blend'=>'application/x-blender',
|
||||
'cc' => 'text/x-c',
|
||||
'cdr' => 'application/coreldraw',
|
||||
'cpp' => 'text/x-c++src',
|
||||
'css'=>'text/css',
|
||||
'c' => 'text/x-c',
|
||||
'c++' => 'text/x-c++src',
|
||||
'doc'=>'application/msword',
|
||||
'docx'=>'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
||||
'dot'=>'application/msword',
|
||||
'dotx'=>'application/vnd.openxmlformats-officedocument.wordprocessingml.template',
|
||||
'dv'=>'video/dv',
|
||||
'epub' => 'application/epub+zip',
|
||||
'exe'=>'application/x-ms-dos-executable',
|
||||
'flac'=>'audio/flac',
|
||||
'gif'=>'image/gif',
|
||||
'gzip'=>'application/x-gzip',
|
||||
'gz'=>'application/x-gzip',
|
||||
'gzip'=>'application/x-gzip',
|
||||
'html'=>'text/html',
|
||||
'htm'=>'text/html',
|
||||
'ics'=>'text/calendar',
|
||||
'ical'=>'text/calendar',
|
||||
'ics'=>'text/calendar',
|
||||
'impress' => 'text/impress',
|
||||
'jpeg'=>'image/jpeg',
|
||||
'jpg'=>'image/jpeg',
|
||||
'js'=>'application/javascript',
|
||||
'keynote'=>'application/x-iwork-keynote-sffkey',
|
||||
'kra'=>'application/x-krita',
|
||||
'm2t'=>'video/mp2t',
|
||||
'm4v'=>'video/mp4',
|
||||
'markdown' => 'text/markdown',
|
||||
'mdown' => 'text/markdown',
|
||||
'md' => 'text/markdown',
|
||||
'mdb'=>'application/msaccess',
|
||||
'mdwn' => 'text/markdown',
|
||||
'mobi' => 'application/x-mobipocket-ebook',
|
||||
'mov'=>'video/quicktime',
|
||||
'mp3'=>'audio/mpeg',
|
||||
'mp4'=>'video/mp4',
|
||||
'mpeg'=>'video/mpeg',
|
||||
'mpg'=>'video/mpeg',
|
||||
'msi'=>'application/x-msi',
|
||||
'numbers'=>'application/x-iwork-numbers-sffnumbers',
|
||||
'odg'=>'application/vnd.oasis.opendocument.graphics',
|
||||
'odp'=>'application/vnd.oasis.opendocument.presentation',
|
||||
'ods'=>'application/vnd.oasis.opendocument.spreadsheet',
|
||||
'odt'=>'application/vnd.oasis.opendocument.text',
|
||||
'oga'=>'audio/ogg',
|
||||
'ogg'=>'audio/ogg',
|
||||
'ogv'=>'video/ogg',
|
||||
'pdf'=>'application/pdf',
|
||||
'png'=>'image/png',
|
||||
'svg'=>'image/svg+xml',
|
||||
'tar'=>'application/x-tar',
|
||||
'tgz'=>'application/x-compressed',
|
||||
'tar.gz'=>'application/x-compressed',
|
||||
'tif'=>'image/tiff',
|
||||
'tiff'=>'image/tiff',
|
||||
'txt'=>'text/plain',
|
||||
'zip'=>'application/zip',
|
||||
'wav'=>'audio/wav',
|
||||
'odt'=>'application/vnd.oasis.opendocument.text',
|
||||
'ods'=>'application/vnd.oasis.opendocument.spreadsheet',
|
||||
'odg'=>'application/vnd.oasis.opendocument.graphics',
|
||||
'odp'=>'application/vnd.oasis.opendocument.presentation',
|
||||
'pages'=>'application/x-iwork-pages-sffpages',
|
||||
'numbers'=>'application/x-iwork-numbers-sffnumbers',
|
||||
'keynote'=>'application/x-iwork-keynote-sffkey',
|
||||
'kra'=>'application/x-krita',
|
||||
'mp3'=>'audio/mpeg',
|
||||
'doc'=>'application/msword',
|
||||
'docx'=>'application/msword',
|
||||
'xls'=>'application/msexcel',
|
||||
'xlsx'=>'application/msexcel',
|
||||
'pdf'=>'application/pdf',
|
||||
'php'=>'application/x-php',
|
||||
'exe'=>'application/x-ms-dos-executable',
|
||||
'msi'=>'application/x-msi',
|
||||
'pl'=>'application/x-pearl',
|
||||
'py'=>'application/x-python',
|
||||
'blend'=>'application/x-blender',
|
||||
'xcf'=>'application/x-gimp',
|
||||
'psd'=>'application/x-photoshop',
|
||||
'xml'=>'application/xml',
|
||||
'avi'=>'video/x-msvideo',
|
||||
'dv'=>'video/dv',
|
||||
'm2t'=>'video/mp2t',
|
||||
'mp4'=>'video/mp4',
|
||||
'm4v'=>'video/mp4',
|
||||
'mpg'=>'video/mpeg',
|
||||
'mpeg'=>'video/mpeg',
|
||||
'mov'=>'video/quicktime',
|
||||
'webm'=>'video/webm',
|
||||
'wmv'=>'video/x-ms-asf',
|
||||
'py'=>'text/x-script.python',
|
||||
'vcf' => 'text/vcard',
|
||||
'vcard' => 'text/vcard',
|
||||
'doc'=>'application/msword',
|
||||
'docx'=>'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
||||
'xls'=>'application/msexcel',
|
||||
'xlsx'=>'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
||||
'png'=>'image/png',
|
||||
'ppt'=>'application/mspowerpoint',
|
||||
'pptx'=>'application/vnd.openxmlformats-officedocument.presentationml.presentation',
|
||||
'sgf' => 'application/sgf',
|
||||
'cdr' => 'application/coreldraw',
|
||||
'impress' => 'text/impress',
|
||||
'ai' => 'application/illustrator',
|
||||
'epub' => 'application/epub+zip',
|
||||
'mobi' => 'application/x-mobipocket-ebook',
|
||||
'md' => 'text/markdown',
|
||||
'markdown' => 'text/markdown',
|
||||
'mdown' => 'text/markdown',
|
||||
'mdwn' => 'text/markdown',
|
||||
'psd'=>'application/x-photoshop',
|
||||
'py'=>'text/x-script.python',
|
||||
'reveal' => 'text/reveal',
|
||||
'c' => 'text/x-c',
|
||||
'cc' => 'text/x-c',
|
||||
'cpp' => 'text/x-c++src',
|
||||
'c++' => 'text/x-c++src',
|
||||
'sh' => 'text/x-shellscript',
|
||||
'bash' => 'text/x-shellscript',
|
||||
'sgf' => 'application/sgf',
|
||||
'sh-lib' => 'text/x-shellscript',
|
||||
'sh' => 'text/x-shellscript',
|
||||
'svg'=>'image/svg+xml',
|
||||
'tar'=>'application/x-tar',
|
||||
'tar.gz'=>'application/x-compressed',
|
||||
'tgz'=>'application/x-compressed',
|
||||
'tiff'=>'image/tiff',
|
||||
'tif'=>'image/tiff',
|
||||
'txt'=>'text/plain',
|
||||
'vcard' => 'text/vcard',
|
||||
'vcf' => 'text/vcard',
|
||||
'wav'=>'audio/wav',
|
||||
'webm'=>'video/webm',
|
||||
'wmv'=>'video/x-ms-asf',
|
||||
'xcf'=>'application/x-gimp',
|
||||
'xls'=>'application/msexcel',
|
||||
'xlsx'=>'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
||||
'xml'=>'application/xml',
|
||||
'zip'=>'application/zip',
|
||||
);
|
||||
|
|
|
@ -11,6 +11,7 @@ class OC_Request {
|
|||
const USER_AGENT_IE = '/MSIE/';
|
||||
// Android Chrome user agent: https://developers.google.com/chrome/mobile/docs/user-agent
|
||||
const USER_AGENT_ANDROID_MOBILE_CHROME = '#Android.*Chrome/[.0-9]*#';
|
||||
const USER_AGENT_FREEBOX = '#^Mozilla/5\.0$#';
|
||||
|
||||
/**
|
||||
* @brief Check overwrite condition
|
||||
|
|
|
@ -153,7 +153,11 @@ class OC_Response {
|
|||
* @param string $type disposition type, either 'attachment' or 'inline'
|
||||
*/
|
||||
static public function setContentDispositionHeader( $filename, $type = 'attachment' ) {
|
||||
if (OC_Request::isUserAgent(array(OC_Request::USER_AGENT_IE, OC_Request::USER_AGENT_ANDROID_MOBILE_CHROME))) {
|
||||
if (OC_Request::isUserAgent(array(
|
||||
OC_Request::USER_AGENT_IE,
|
||||
OC_Request::USER_AGENT_ANDROID_MOBILE_CHROME,
|
||||
OC_Request::USER_AGENT_FREEBOX
|
||||
))) {
|
||||
header( 'Content-Disposition: ' . rawurlencode($type) . '; filename="' . rawurlencode( $filename ) . '"' );
|
||||
} else {
|
||||
header( 'Content-Disposition: ' . rawurlencode($type) . '; filename*=UTF-8\'\'' . rawurlencode( $filename )
|
||||
|
|
|
@ -138,6 +138,10 @@ class Server extends SimpleContainer implements IServerContainer {
|
|||
$this->registerService('UserCache', function($c) {
|
||||
return new UserCache();
|
||||
});
|
||||
$this->registerService('MemCacheFactory', function ($c) {
|
||||
$instanceId = \OC_Util::getInstanceId();
|
||||
return new \OC\Memcache\Factory($instanceId);
|
||||
});
|
||||
$this->registerService('ActivityManager', function($c) {
|
||||
return new ActivityManager();
|
||||
});
|
||||
|
@ -297,6 +301,15 @@ class Server extends SimpleContainer implements IServerContainer {
|
|||
return $this->query('UserCache');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an \OCP\CacheFactory instance
|
||||
*
|
||||
* @return \OCP\CacheFactory
|
||||
*/
|
||||
function getMemCacheFactory() {
|
||||
return $this->query('MemCacheFactory');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current session
|
||||
*
|
||||
|
|
|
@ -788,8 +788,12 @@ class OC_Util {
|
|||
}
|
||||
|
||||
$fp = @fopen($testFile, 'w');
|
||||
@fwrite($fp, $testContent);
|
||||
@fclose($fp);
|
||||
if (!$fp) {
|
||||
throw new OC\HintException('Can\'t create test file to check for working .htaccess file.',
|
||||
'Make sure it is possible for the webserver to write to '.$testFile);
|
||||
}
|
||||
fwrite($fp, $testContent);
|
||||
fclose($fp);
|
||||
|
||||
// accessing the file via http
|
||||
$url = OC_Helper::makeURLAbsolute(OC::$WEBROOT.'/data'.$fileName);
|
||||
|
|
28
lib/public/icachefactory.php
Normal file
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
/**
|
||||
* Copyright (c) 2014 Robin Appelman <icewind@owncloud.com>
|
||||
* This file is licensed under the Affero General Public License version 3 or
|
||||
* later.
|
||||
* See the COPYING-README file.
|
||||
*/
|
||||
|
||||
namespace OCP;
|
||||
|
||||
interface ICacheFactory{
|
||||
/**
|
||||
* Get a memory cache instance
|
||||
*
|
||||
* All entries added trough the cache instance will be namespaced by $prefix to prevent collisions between apps
|
||||
*
|
||||
* @param string $prefix
|
||||
* @return \OCP\ICache
|
||||
*/
|
||||
public function create($prefix = '');
|
||||
|
||||
/**
|
||||
* Check if any memory cache backend is available
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isAvailable();
|
||||
}
|
|
@ -141,6 +141,13 @@ interface IServerContainer {
|
|||
*/
|
||||
function getCache();
|
||||
|
||||
/**
|
||||
* Returns an \OCP\CacheFactory instance
|
||||
*
|
||||
* @return \OCP\ICacheFactory
|
||||
*/
|
||||
function getMemCacheFactory();
|
||||
|
||||
/**
|
||||
* Returns the current session
|
||||
*
|
||||
|
|
|
@ -1152,7 +1152,7 @@ class Share {
|
|||
$select = '`*PREFIX*share`.`id`, `item_type`, `item_source`, `*PREFIX*share`.`parent`, `uid_owner`, '
|
||||
.'`share_type`, `share_with`, `file_source`, `path`, `file_target`, '
|
||||
.'`permissions`, `expiration`, `storage`, `*PREFIX*filecache`.`parent` as `file_parent`, '
|
||||
.'`name`, `mtime`, `mimetype`, `mimepart`, `size`, `encrypted`, `etag`, `mail_send`';
|
||||
.'`name`, `mtime`, `mimetype`, `mimepart`, `size`, `unencrypted_size`, `encrypted`, `etag`, `mail_send`';
|
||||
} else {
|
||||
$select = '`*PREFIX*share`.`id`, `item_type`, `item_source`, `item_target`,
|
||||
`*PREFIX*share`.`parent`, `share_type`, `share_with`, `uid_owner`,
|
||||
|
|
|
@ -88,14 +88,18 @@ class Util {
|
|||
* @param Exception $ex exception to log
|
||||
*/
|
||||
public static function logException( $app, \Exception $ex ) {
|
||||
$message = $ex->getMessage();
|
||||
$class = get_class($ex);
|
||||
if ($class !== 'Exception') {
|
||||
$message = $class . ': ';
|
||||
}
|
||||
$message .= $ex->getMessage();
|
||||
if ($ex->getCode()) {
|
||||
$message .= ' [' . $ex->getCode() . ']';
|
||||
}
|
||||
\OCP\Util::writeLog($app, 'Exception: ' . $message, \OCP\Util::FATAL);
|
||||
if (defined('DEBUG') and DEBUG) {
|
||||
// also log stack trace
|
||||
$stack = explode('#', $ex->getTraceAsString());
|
||||
$stack = explode("\n", $ex->getTraceAsString());
|
||||
// first element is empty
|
||||
array_shift($stack);
|
||||
foreach ($stack as $s) {
|
||||
|
@ -462,4 +466,23 @@ class Util {
|
|||
public static function maxUploadFilesize($dir) {
|
||||
return \OC_Helper::maxUploadFilesize($dir);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate free space left within user quota
|
||||
*
|
||||
* @param $dir the current folder where the user currently operates
|
||||
* @return number of bytes representing
|
||||
*/
|
||||
public static function freeSpace($dir) {
|
||||
return \OC_Helper::freeSpace($dir);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate PHP upload limit
|
||||
*
|
||||
* @return number of bytes representing
|
||||
*/
|
||||
public static function uploadLimit() {
|
||||
return \OC_Helper::uploadLimit();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
CC BY 3.0
|
||||
http://thenounproject.com/en-us/noun/printer/#icon-No109
|
Before Width: | Height: | Size: 342 B |
|
@ -1,10 +0,0 @@
|
|||
<?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" enable-background="new 0 0 100 100" xml:space="preserve" height="16px" viewBox="0 0 100 100" width="16px" version="1.1" y="0px" x="0px" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/"><g fill="#4d4d4d">
|
||||
<rect height="19" width="4" y="45" x="75"/>
|
||||
<polygon points="21 0 21 19 25 19 25 4 75 4 75 19 79 19 79 0"/>
|
||||
<polygon points="75 45 75 96 44 96 44 77 25 77 25 45 21 45 21 80 41 100 79 100 79 45"/>
|
||||
<rect height="3" width="38" y="45" x="31"/>
|
||||
<rect height="3" width="38" y="56" x="31"/>
|
||||
<rect height="3" width="38" y="67" x="31"/>
|
||||
<path d="m0 21v48h19v-10h-9v-28h80v28h-9v10h19v-48h-100zm97 7h-4v-4h4v4z"/>
|
||||
</g></svg>
|
Before Width: | Height: | Size: 807 B |
|
@ -9,9 +9,11 @@
|
|||
|
||||
|
||||
<ul id="leftcontent" class="applist">
|
||||
<?php if(OC_Config::getValue('appstoreenabled', true) === true): ?>
|
||||
<li>
|
||||
<a class="app-external" target="_blank" href="http://owncloud.org/dev"><?php p($l->t('Add your App'));?> …</a>
|
||||
</li>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php foreach($_['apps'] as $app):?>
|
||||
<li <?php if($app['active']) print_unescaped('class="active"')?> data-id="<?php p($app['id']) ?>"
|
||||
|
@ -24,9 +26,11 @@
|
|||
</li>
|
||||
<?php endforeach;?>
|
||||
|
||||
<?php if(OC_Config::getValue('appstoreenabled', true) === true): ?>
|
||||
<li>
|
||||
<a class="app-external" target="_blank" href="http://apps.owncloud.com"><?php p($l->t('More Apps'));?> …</a>
|
||||
</li>
|
||||
<?php endif; ?>
|
||||
</ul>
|
||||
<div id="rightcontent">
|
||||
<div class="appinfo">
|
||||
|
|
|
@ -29,25 +29,52 @@
|
|||
* environment variable to the apps name, for example "core" or "files_encryption".
|
||||
* Multiple apps can be specified by separating them with space.
|
||||
*
|
||||
* Setting the environment variable NOCOVERAGE to 1 will disable the coverage
|
||||
* preprocessor, which is needed to be able to debug tests properly in a browser.
|
||||
*/
|
||||
|
||||
/* jshint node: true */
|
||||
module.exports = function(config) {
|
||||
|
||||
function findApps() {
|
||||
/*
|
||||
var fs = require('fs');
|
||||
var apps = fs.readdirSync('apps');
|
||||
return apps;
|
||||
*/
|
||||
// other apps tests don't run yet... needs further research / clean up
|
||||
return ['files'];
|
||||
}
|
||||
|
||||
// respect NOCOVERAGE env variable
|
||||
// it is useful to disable coverage for debugging
|
||||
// because the coverage preprocessor will wrap the JS files somehow
|
||||
var enableCoverage = !parseInt(process.env.NOCOVERAGE, 10);
|
||||
console.log('Coverage preprocessor: ', enableCoverage?'enabled':'disabled');
|
||||
|
||||
// default apps to test when none is specified (TODO: read from filesystem ?)
|
||||
var defaultApps = 'core files';
|
||||
var appsToTest = process.env.KARMA_TESTSUITE || defaultApps;
|
||||
var appsToTest = process.env.KARMA_TESTSUITE;
|
||||
if (appsToTest) {
|
||||
appsToTest = appsToTest.split(' ');
|
||||
}
|
||||
else {
|
||||
appsToTest = ['core'].concat(findApps());
|
||||
}
|
||||
|
||||
console.log('Apps to test: ', appsToTest);
|
||||
|
||||
// read core files from core.json,
|
||||
// these are required by all apps so always need to be loaded
|
||||
// note that the loading order is important that's why they
|
||||
// are specified in a separate file
|
||||
var corePath = 'core/js/';
|
||||
var coreFiles = require('../' + corePath + 'core.json').modules;
|
||||
var coreModule = require('../' + corePath + 'core.json');
|
||||
var testCore = false;
|
||||
var files = [];
|
||||
var index;
|
||||
var preprocessors = {};
|
||||
|
||||
// find out what apps to test from appsToTest
|
||||
appsToTest = appsToTest.split(' ');
|
||||
index = appsToTest.indexOf('core');
|
||||
if (index > -1) {
|
||||
appsToTest.splice(index, 1);
|
||||
|
@ -60,11 +87,23 @@ module.exports = function(config) {
|
|||
// core mocks
|
||||
files.push(corePath + 'tests/specHelper.js');
|
||||
|
||||
// add core files
|
||||
for ( var i = 0; i < coreFiles.length; i++ ) {
|
||||
files.push( corePath + coreFiles[i] );
|
||||
// add core library files
|
||||
for ( var i = 0; i < coreModule.libraries.length; i++ ) {
|
||||
var srcFile = corePath + coreModule.libraries[i];
|
||||
files.push(srcFile);
|
||||
}
|
||||
|
||||
// add core modules files
|
||||
for ( var i = 0; i < coreModule.modules.length; i++ ) {
|
||||
var srcFile = corePath + coreModule.modules[i];
|
||||
files.push(srcFile);
|
||||
if (enableCoverage) {
|
||||
preprocessors[srcFile] = 'coverage';
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: settings pages
|
||||
|
||||
// need to test the core app as well ?
|
||||
if (testCore) {
|
||||
// core tests
|
||||
|
@ -73,7 +112,11 @@ module.exports = function(config) {
|
|||
|
||||
for ( var i = 0; i < appsToTest.length; i++ ) {
|
||||
// add app JS
|
||||
files.push('apps/' + appsToTest[i] + '/js/*.js');
|
||||
var srcFile = 'apps/' + appsToTest[i] + '/js/*.js';
|
||||
files.push(srcFile);
|
||||
if (enableCoverage) {
|
||||
preprocessors[srcFile] = 'coverage';
|
||||
}
|
||||
// add test specs
|
||||
files.push('apps/' + appsToTest[i] + '/tests/js/*.js');
|
||||
}
|
||||
|
@ -83,7 +126,6 @@ module.exports = function(config) {
|
|||
// base path, that will be used to resolve files and exclude
|
||||
basePath: '..',
|
||||
|
||||
|
||||
// frameworks to use
|
||||
frameworks: ['jasmine'],
|
||||
|
||||
|
@ -106,9 +148,7 @@ module.exports = function(config) {
|
|||
// web server port
|
||||
port: 9876,
|
||||
|
||||
preprocessors: {
|
||||
'apps/files/js/*.js': 'coverage'
|
||||
},
|
||||
preprocessors: preprocessors,
|
||||
|
||||
coverageReporter: {
|
||||
dir:'tests/karma-coverage',
|
||||
|
|
62
tests/lib/errorHandler.php
Normal file
|
@ -0,0 +1,62 @@
|
|||
<?php
|
||||
/**
|
||||
* ownCloud
|
||||
*
|
||||
* @author Bjoern Schiessle
|
||||
* @copyright 2014 Bjoern Schiessle <schiessle@owncloud.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
class Test_ErrorHandler extends \PHPUnit_Framework_TestCase {
|
||||
|
||||
/**
|
||||
* @brief provide username, password combinations for testRemovePassword
|
||||
* @return array
|
||||
*/
|
||||
function passwordProvider() {
|
||||
return array(
|
||||
array('user', 'password'),
|
||||
array('user@owncloud.org', 'password'),
|
||||
array('user', 'pass@word'),
|
||||
array('us:er', 'password'),
|
||||
array('user', 'pass:word'),
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider passwordProvider
|
||||
* @param string $username
|
||||
* @param string $password
|
||||
*/
|
||||
function testRemovePassword($username, $password) {
|
||||
$url = 'http://'.$username.':'.$password.'@owncloud.org';
|
||||
$expectedResult = 'http://xxx:xxx@owncloud.org';
|
||||
$result = TestableErrorHandler::testRemovePassword($url);
|
||||
|
||||
$this->assertEquals($expectedResult, $result);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief dummy class to access protected methods of \OC\Log\ErrorHandler
|
||||
*/
|
||||
class TestableErrorHandler extends \OC\Log\ErrorHandler {
|
||||
public static function testRemovePassword($msg) {
|
||||
return self::removePassword($msg);
|
||||
}
|
||||
}
|
|
@ -118,6 +118,21 @@ class Test_Request extends PHPUnit_Framework_TestCase {
|
|||
),
|
||||
true
|
||||
),
|
||||
array(
|
||||
'Mozilla/5.0 (X11; Linux i686; rv:24.0) Gecko/20100101 Firefox/24.0',
|
||||
OC_Request::USER_AGENT_FREEBOX,
|
||||
false
|
||||
),
|
||||
array(
|
||||
'Mozilla/5.0',
|
||||
OC_Request::USER_AGENT_FREEBOX,
|
||||
true
|
||||
),
|
||||
array(
|
||||
'Fake Mozilla/5.0',
|
||||
OC_Request::USER_AGENT_FREEBOX,
|
||||
false
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|