Merge branch 'master' into fix-language-detection

This commit is contained in:
Thomas Müller 2013-10-24 19:27:33 +02:00
commit 66813e9df6
65 changed files with 4039 additions and 1089 deletions

View File

@ -8,7 +8,10 @@ If you have questions about how to install or use ownCloud, please direct these
### Guidelines
* Please search the existing issues first, it's likely that your issue was already reported or even fixed.
* This repository is *only* for issues within the ownCloud core code. This also includes the apps: files, encryption, external storage, sharing, deleted files, versions, LDAP, and WebDAV Auth
- Go to one of the repositories, click "issues" and type any word in the top search/command bar.
- You can also filter by appending e. g. "state:open" to the search string.
- More info on [search syntax within github](https://help.github.com/articles/searching-issues)
* This repository ([core](https://github.com/owncloud/core/issues)) is *only* for issues within the ownCloud core code. This also includes the apps: files, encryption, external storage, sharing, deleted files, versions, LDAP, and WebDAV Auth
* The issues in other components should be reported in their respective repositories:
- [Android client](https://github.com/owncloud/android/issues)
- [iOS client](https://github.com/owncloud/ios-issues/issues)

View File

@ -20,15 +20,6 @@ if($source) {
OC_JSON::callCheck();
}
if($filename == '') {
OCP\JSON::error(array("data" => array( "message" => "Empty Filename" )));
exit();
}
if(strpos($filename, '/')!==false) {
OCP\JSON::error(array("data" => array( "message" => "Invalid Filename" )));
exit();
}
function progress($notification_code, $severity, $message, $message_code, $bytes_transferred, $bytes_max) {
static $filesize = 0;
static $lastsize = 0;
@ -44,7 +35,7 @@ function progress($notification_code, $severity, $message, $message_code, $bytes
if (!isset($filesize)) {
} else {
$progress = (int)(($bytes_transferred/$filesize)*100);
if($progress>$lastsize) {//limit the number or messages send
if($progress>$lastsize) { //limit the number or messages send
$eventSource->send('progress', $progress);
}
$lastsize=$progress;
@ -54,11 +45,40 @@ function progress($notification_code, $severity, $message, $message_code, $bytes
}
}
$l10n = \OC_L10n::get('files');
$result = array(
'success' => false,
'data' => NULL
);
if(trim($filename) === '') {
$result['data'] = array('message' => $l10n->t('File name cannot not be empty.'));
OCP\JSON::error($result);
exit();
}
if(strpos($filename, '/') !== false) {
$result['data'] = array('message' => $l10n->t('File name must not contain "/". Please choose a different name.'));
OCP\JSON::error($result);
exit();
}
//TODO why is stripslashes used on foldername in newfolder.php but not here?
$target = $dir.'/'.$filename;
if (\OC\Files\Filesystem::file_exists($target)) {
$result['data'] = array('message' => $l10n->t(
'The name %s is already used in the folder %s. Please choose a different name.',
array($filename, $dir))
);
OCP\JSON::error($result);
exit();
}
if($source) {
if(substr($source, 0, 8)!='https://' and substr($source, 0, 7)!='http://') {
OCP\JSON::error(array("data" => array( "message" => "Not a valid source" )));
OCP\JSON::error(array('data' => array( 'message' => $l10n->t('Not a valid source') )));
exit();
}
@ -71,7 +91,7 @@ if($source) {
$id = $meta['fileid'];
$eventSource->send('success', array('mime'=>$mime, 'size'=>\OC\Files\Filesystem::filesize($target), 'id' => $id));
} else {
$eventSource->send('error', "Error while downloading ".$source. ' to '.$target);
$eventSource->send('error', $l10n->t('Error while downloading %s to %s', array($source, $target)));
}
$eventSource->close();
exit();
@ -104,4 +124,4 @@ if($source) {
}
}
OCP\JSON::error(array("data" => array( "message" => "Error when creating the file" )));
OCP\JSON::error(array('data' => array( 'message' => $l10n->t('Error when creating the file') )));

View File

@ -10,25 +10,47 @@ OCP\JSON::callCheck();
$dir = isset( $_POST['dir'] ) ? stripslashes($_POST['dir']) : '';
$foldername = isset( $_POST['foldername'] ) ? stripslashes($_POST['foldername']) : '';
if(trim($foldername) == '') {
OCP\JSON::error(array("data" => array( "message" => "Empty Foldername" )));
exit();
}
if(strpos($foldername, '/')!==false) {
OCP\JSON::error(array("data" => array( "message" => "Invalid Foldername" )));
$l10n = \OC_L10n::get('files');
$result = array(
'success' => false,
'data' => NULL
);
if(trim($foldername) === '') {
$result['data'] = array('message' => $l10n->t('Folder name cannot not be empty.'));
OCP\JSON::error($result);
exit();
}
if(\OC\Files\Filesystem::mkdir($dir . '/' . stripslashes($foldername))) {
if ( $dir != '/') {
if(strpos($foldername, '/') !== false) {
$result['data'] = array('message' => $l10n->t('Folder name must not contain "/". Please choose a different name.'));
OCP\JSON::error($result);
exit();
}
//TODO why is stripslashes used on foldername here but not in newfile.php?
$target = $dir . '/' . stripslashes($foldername);
if (\OC\Files\Filesystem::file_exists($target)) {
$result['data'] = array('message' => $l10n->t(
'The name %s is already used in the folder %s. Please choose a different name.',
array($foldername, $dir))
);
OCP\JSON::error($result);
exit();
}
if(\OC\Files\Filesystem::mkdir($target)) {
if ( $dir !== '/') {
$path = $dir.'/'.$foldername;
} else {
$path = '/'.$foldername;
}
$meta = \OC\Files\Filesystem::getFileInfo($path);
$id = $meta['fileid'];
OCP\JSON::success(array("data" => array('id'=>$id)));
OCP\JSON::success(array('data' => array('id' => $id)));
exit();
}
OCP\JSON::error(array("data" => array( "message" => "Error when creating the folder" )));
OCP\JSON::error(array('data' => array( 'message' => $l10n->t('Error when creating the folder') )));

View File

@ -48,6 +48,7 @@ $defaults = new OC_Defaults();
$server->addPlugin(new Sabre_DAV_Auth_Plugin($authBackend, $defaults->getName()));
$server->addPlugin(new Sabre_DAV_Locks_Plugin($lockBackend));
$server->addPlugin(new Sabre_DAV_Browser_Plugin(false)); // Show something in the Browser, but no upload
$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());

View File

@ -49,7 +49,13 @@
background-repeat:no-repeat; cursor:pointer; }
#new>ul>li>p { cursor:pointer; padding-top: 7px; padding-bottom: 7px;}
#new .error, #fileList .error {
color: #e9322d;
border-color: #e9322d;
-webkit-box-shadow: 0 0 6px #f8b9b7;
-moz-box-shadow: 0 0 6px #f8b9b7;
box-shadow: 0 0 6px #f8b9b7;
}
/* FILE TABLE */

View File

@ -21,13 +21,13 @@ function supportAjaxUploadWithProgress() {
var fi = document.createElement('INPUT');
fi.type = 'file';
return 'files' in fi;
};
}
// Are progress events supported?
function supportAjaxUploadProgressEvents() {
var xhr = new XMLHttpRequest();
return !! (xhr && ('upload' in xhr) && ('onprogress' in xhr.upload));
};
}
// Is FormData supported?
function supportFormData() {
@ -53,12 +53,12 @@ OC.Upload = {
*/
cancelUploads:function() {
this.log('canceling uploads');
jQuery.each(this._uploads,function(i, jqXHR){
jQuery.each(this._uploads,function(i, jqXHR) {
jqXHR.abort();
});
this._uploads = [];
},
rememberUpload:function(jqXHR){
rememberUpload:function(jqXHR) {
if (jqXHR) {
this._uploads.push(jqXHR);
}
@ -68,10 +68,10 @@ OC.Upload = {
* returns true if any hxr has the state 'pending'
* @returns {boolean}
*/
isProcessing:function(){
isProcessing:function() {
var count = 0;
jQuery.each(this._uploads,function(i, data){
jQuery.each(this._uploads,function(i, data) {
if (data.state() === 'pending') {
count++;
}
@ -114,7 +114,7 @@ OC.Upload = {
* handle skipping an upload
* @param {object} data
*/
onSkip:function(data){
onSkip:function(data) {
this.log('skip', null, data);
this.deleteUpload(data);
},
@ -122,12 +122,12 @@ OC.Upload = {
* handle replacing a file on the server with an uploaded file
* @param {object} data
*/
onReplace:function(data){
onReplace:function(data) {
this.log('replace', null, data);
if (data.data){
if (data.data) {
data.data.append('resolution', 'replace');
} else {
data.formData.push({name:'resolution',value:'replace'}); //hack for ie8
data.formData.push({name:'resolution', value:'replace'}); //hack for ie8
}
data.submit();
},
@ -135,12 +135,12 @@ OC.Upload = {
* handle uploading a file and letting the server decide a new name
* @param {object} data
*/
onAutorename:function(data){
onAutorename:function(data) {
this.log('autorename', null, data);
if (data.data) {
data.data.append('resolution', 'autorename');
} else {
data.formData.push({name:'resolution',value:'autorename'}); //hack for ie8
data.formData.push({name:'resolution', value:'autorename'}); //hack for ie8
}
data.submit();
},
@ -162,7 +162,7 @@ OC.Upload = {
* @param {function} callbacks.onChooseConflicts
* @param {function} callbacks.onCancel
*/
checkExistingFiles: function (selection, callbacks){
checkExistingFiles: function (selection, callbacks) {
// TODO check filelist before uploading and show dialog on conflicts, use callbacks
callbacks.onNoConflicts(selection);
}
@ -215,7 +215,7 @@ $(document).ready(function() {
var selection = data.originalFiles.selection;
// add uploads
if ( selection.uploads.length < selection.filesToUpload ){
if ( selection.uploads.length < selection.filesToUpload ) {
// remember upload
selection.uploads.push(data);
}
@ -335,7 +335,7 @@ $(document).ready(function() {
delete data.jqXHR;
if(typeof result[0] === 'undefined') {
if (typeof result[0] === 'undefined') {
data.textStatus = 'servererror';
data.errorThrown = t('files', 'Could not get result from server.');
var fu = $(this).data('blueimp-fileupload') || $(this).data('fileupload');
@ -368,13 +368,13 @@ $(document).ready(function() {
var fileupload = $('#file_upload_start').fileupload(file_upload_param);
window.file_upload_param = fileupload;
if(supportAjaxUploadWithProgress()) {
if (supportAjaxUploadWithProgress()) {
// add progress handlers
fileupload.on('fileuploadadd', function(e, data) {
OC.Upload.log('progress handle fileuploadadd', e, data);
//show cancel button
//if(data.dataType !== 'iframe') { //FIXME when is iframe used? only for ie?
//if (data.dataType !== 'iframe') { //FIXME when is iframe used? only for ie?
// $('#uploadprogresswrapper input.stop').show();
//}
});
@ -419,7 +419,9 @@ $(document).ready(function() {
// http://stackoverflow.com/a/6700/11236
var size = 0, key;
for (key in obj) {
if (obj.hasOwnProperty(key)) size++;
if (obj.hasOwnProperty(key)) {
size++;
}
}
return size;
};
@ -432,56 +434,61 @@ $(document).ready(function() {
});
//add multiply file upload attribute to all browsers except konqueror (which crashes when it's used)
if(navigator.userAgent.search(/konqueror/i)==-1){
$('#file_upload_start').attr('multiple','multiple');
if (navigator.userAgent.search(/konqueror/i) === -1) {
$('#file_upload_start').attr('multiple', 'multiple');
}
//if the breadcrumb is to long, start by replacing foldernames with '...' except for the current folder
var crumb=$('div.crumb').first();
while($('div.controls').height()>40 && crumb.next('div.crumb').length>0){
while($('div.controls').height() > 40 && crumb.next('div.crumb').length > 0) {
crumb.children('a').text('...');
crumb=crumb.next('div.crumb');
crumb = crumb.next('div.crumb');
}
//if that isn't enough, start removing items from the breacrumb except for the current folder and it's parent
var crumb=$('div.crumb').first();
var next=crumb.next('div.crumb');
while($('div.controls').height()>40 && next.next('div.crumb').length>0){
var crumb = $('div.crumb').first();
var next = crumb.next('div.crumb');
while($('div.controls').height()>40 && next.next('div.crumb').length > 0) {
crumb.remove();
crumb=next;
next=crumb.next('div.crumb');
crumb = next;
next = crumb.next('div.crumb');
}
//still not enough, start shorting down the current folder name
var crumb=$('div.crumb>a').last();
while($('div.controls').height()>40 && crumb.text().length>6){
var text=crumb.text()
text=text.substr(0,text.length-6)+'...';
while($('div.controls').height() > 40 && crumb.text().length > 6) {
var text=crumb.text();
text = text.substr(0,text.length-6)+'...';
crumb.text(text);
}
$(document).click(function(){
$(document).click(function() {
$('#new>ul').hide();
$('#new').removeClass('active');
$('#new li').each(function(i,element){
if($(element).children('p').length==0){
if ($('#new .error').length > 0) {
$('#new .error').tipsy('hide');
}
$('#new li').each(function(i,element) {
if ($(element).children('p').length === 0) {
$(element).children('form').remove();
$(element).append('<p>'+$(element).data('text')+'</p>');
}
});
});
$('#new').click(function(event){
$('#new').click(function(event) {
event.stopPropagation();
});
$('#new>a').click(function(){
$('#new>a').click(function() {
$('#new>ul').toggle();
$('#new').toggleClass('active');
});
$('#new li').click(function(){
if($(this).children('p').length==0){
$('#new li').click(function() {
if ($(this).children('p').length === 0) {
return;
}
$('#new .error').tipsy('hide');
$('#new li').each(function(i,element){
if($(element).children('p').length==0){
$('#new li').each(function(i,element) {
if ($(element).children('p').length === 0) {
$(element).children('form').remove();
$(element).append('<p>'+$(element).data('text')+'</p>');
}
@ -491,132 +498,164 @@ $(document).ready(function() {
var text=$(this).children('p').text();
$(this).data('text',text);
$(this).children('p').remove();
// add input field
var form=$('<form></form>');
var input=$('<input type="text">');
form.append(input);
$(this).append(form);
var checkInput = function () {
var filename = input.val();
if (type === 'web' && filename.length === 0) {
throw t('files', 'URL cannot be empty');
} else if (type !== 'web' && !Files.isFileNameValid(filename)) {
// Files.isFileNameValid(filename) throws an exception itself
} else if ($('#dir').val() === '/' && filename === 'Shared') {
throw t('files', 'In the home folder \'Shared\' is a reserved filename');
} else if (FileList.inList(filename)) {
throw t('files', '{new_name} already exists', {new_name: filename});
} else {
return true;
}
};
// verify filename on typing
input.keyup(function(event) {
try {
checkInput();
input.tipsy('hide');
input.removeClass('error');
} catch (error) {
input.attr('title', error);
input.tipsy({gravity: 'w', trigger: 'manual'});
input.tipsy('show');
input.addClass('error');
}
});
input.focus();
form.submit(function(event){
form.submit(function(event) {
event.stopPropagation();
event.preventDefault();
var newname=input.val();
if(type == 'web' && newname.length == 0) {
OC.Notification.show(t('files', 'URL cannot be empty.'));
return false;
} else if (type != 'web' && !Files.isFileNameValid(newname)) {
return false;
} else if( type == 'folder' && $('#dir').val() == '/' && newname == 'Shared') {
OC.Notification.show(t('files','Invalid folder name. Usage of \'Shared\' is reserved by ownCloud'));
return false;
}
if (FileList.lastAction) {
FileList.lastAction();
}
var name = getUniqueName(newname);
if (newname != name) {
FileList.checkName(name, newname, true);
var hidden = true;
} else {
var hidden = false;
}
switch(type){
case 'file':
$.post(
OC.filePath('files','ajax','newfile.php'),
{dir:$('#dir').val(),filename:name},
function(result){
if (result.status == 'success') {
var date=new Date();
// TODO: ideally addFile should be able to receive
// all attributes and set them automatically,
// and also auto-load the preview
var tr = FileList.addFile(name,0,date,false,hidden);
tr.attr('data-size',result.data.size);
tr.attr('data-mime',result.data.mime);
tr.attr('data-id', result.data.id);
tr.find('.filesize').text(humanFileSize(result.data.size));
var path = getPathForPreview(name);
lazyLoadPreview(path, result.data.mime, function(previewpath){
tr.find('td.filename').attr('style','background-image:url('+previewpath+')');
});
FileActions.display(tr.find('td.filename'), true);
} else {
OC.dialogs.alert(result.data.message, t('core', 'Error'));
try {
checkInput();
var newname = input.val();
if (FileList.lastAction) {
FileList.lastAction();
}
var name = getUniqueName(newname);
if (newname !== name) {
FileList.checkName(name, newname, true);
var hidden = true;
} else {
var hidden = false;
}
switch(type) {
case 'file':
$.post(
OC.filePath('files', 'ajax', 'newfile.php'),
{dir:$('#dir').val(), filename:name},
function(result) {
if (result.status === 'success') {
var date = new Date();
// TODO: ideally addFile should be able to receive
// all attributes and set them automatically,
// and also auto-load the preview
var tr = FileList.addFile(name, 0, date, false, hidden);
tr.attr('data-size', result.data.size);
tr.attr('data-mime', result.data.mime);
tr.attr('data-id', result.data.id);
tr.find('.filesize').text(humanFileSize(result.data.size));
var path = getPathForPreview(name);
lazyLoadPreview(path, result.data.mime, function(previewpath) {
tr.find('td.filename').attr('style','background-image:url('+previewpath+')');
});
FileActions.display(tr.find('td.filename'), true);
} else {
OC.dialogs.alert(result.data.message, t('core', 'Could not create file'));
}
}
}
);
break;
case 'folder':
$.post(
OC.filePath('files','ajax','newfolder.php'),
{dir:$('#dir').val(),foldername:name},
function(result){
if (result.status == 'success') {
var date=new Date();
FileList.addDir(name,0,date,hidden);
var tr=$('tr').filterAttr('data-file',name);
tr.attr('data-id', result.data.id);
} else {
OC.dialogs.alert(result.data.message, t('core', 'Error'));
);
break;
case 'folder':
$.post(
OC.filePath('files','ajax','newfolder.php'),
{dir:$('#dir').val(), foldername:name},
function(result) {
if (result.status === 'success') {
var date=new Date();
FileList.addDir(name, 0, date, hidden);
var tr=$('tr[data-file="'+name+'"]');
tr.attr('data-id', result.data.id);
} else {
OC.dialogs.alert(result.data.message, t('core', 'Could not create folder'));
}
}
);
break;
case 'web':
if (name.substr(0,8) !== 'https://' && name.substr(0,7) !== 'http://') {
name = 'http://' + name;
}
);
break;
case 'web':
if(name.substr(0,8)!='https://' && name.substr(0,7)!='http://'){
name='http://'+name;
}
var localName=name;
if(localName.substr(localName.length-1,1)=='/'){//strip /
localName=localName.substr(0,localName.length-1)
}
if(localName.indexOf('/')){//use last part of url
localName=localName.split('/').pop();
} else { //or the domain
localName=(localName.match(/:\/\/(.[^\/]+)/)[1]).replace('www.','');
}
localName = getUniqueName(localName);
//IE < 10 does not fire the necessary events for the progress bar.
if($('html.lte9').length === 0) {
$('#uploadprogressbar').progressbar({value:0});
$('#uploadprogressbar').fadeIn();
}
var eventSource=new OC.EventSource(OC.filePath('files','ajax','newfile.php'),{dir:$('#dir').val(),source:name,filename:localName});
eventSource.listen('progress',function(progress){
var localName=name;
if (localName.substr(localName.length-1,1)==='/') {//strip /
localName=localName.substr(0,localName.length-1);
}
if (localName.indexOf('/')) {//use last part of url
localName=localName.split('/').pop();
} else { //or the domain
localName=(localName.match(/:\/\/(.[^\/]+)/)[1]).replace('www.','');
}
localName = getUniqueName(localName);
//IE < 10 does not fire the necessary events for the progress bar.
if($('html.lte9').length === 0) {
$('#uploadprogressbar').progressbar('value',progress);
if ($('html.lte9').length === 0) {
$('#uploadprogressbar').progressbar({value:0});
$('#uploadprogressbar').fadeIn();
}
});
eventSource.listen('success',function(data){
var mime=data.mime;
var size=data.size;
var id=data.id;
$('#uploadprogressbar').fadeOut();
var date=new Date();
FileList.addFile(localName,size,date,false,hidden);
var tr=$('tr').filterAttr('data-file',localName);
tr.data('mime',mime).data('id',id);
tr.attr('data-id', id);
var path = $('#dir').val()+'/'+localName;
lazyLoadPreview(path, mime, function(previewpath){
tr.find('td.filename').attr('style','background-image:url('+previewpath+')');
var eventSource=new OC.EventSource(OC.filePath('files','ajax','newfile.php'),{dir:$('#dir').val(),source:name,filename:localName});
eventSource.listen('progress',function(progress) {
//IE < 10 does not fire the necessary events for the progress bar.
if ($('html.lte9').length === 0) {
$('#uploadprogressbar').progressbar('value',progress);
}
});
});
eventSource.listen('error',function(error){
$('#uploadprogressbar').fadeOut();
alert(error);
});
break;
eventSource.listen('success',function(data) {
var mime = data.mime;
var size = data.size;
var id = data.id;
$('#uploadprogressbar').fadeOut();
var date = new Date();
FileList.addFile(localName, size, date, false, hidden);
var tr = $('tr[data-file="'+localName+'"]');
tr.data('mime', mime).data('id', id);
tr.attr('data-id', id);
var path = $('#dir').val()+'/'+localName;
lazyLoadPreview(path, mime, function(previewpath) {
tr.find('td.filename').attr('style', 'background-image:url('+previewpath+')');
});
FileActions.display(tr.find('td.filename'), true);
});
eventSource.listen('error',function(error) {
$('#uploadprogressbar').fadeOut();
alert(error);
});
break;
}
var li=form.parent();
form.remove();
/* workaround for IE 9&10 click event trap, 2 lines: */
$('input').first().focus();
$('#content').focus();
li.append('<p>'+li.data('text')+'</p>');
$('#new>a').click();
} catch (error) {
input.attr('title', error);
input.tipsy({gravity: 'w', trigger: 'manual'});
input.tipsy('show');
input.addClass('error');
}
var li=form.parent();
form.remove();
/* workaround for IE 9&10 click event trap, 2 lines: */
$('input').first().focus();
$('#content').focus();
li.append('<p>'+li.data('text')+'</p>');
$('#new>a').click();
});
});
window.file_upload_param = file_upload_param;

View File

@ -1,7 +1,7 @@
var FileList={
useUndo:true,
postProcessList: function(){
$('#fileList tr').each(function(){
postProcessList: function() {
$('#fileList tr').each(function() {
//little hack to set unescape filenames in attribute
$(this).attr('data-file',decodeURIComponent($(this).attr('data-file')));
});
@ -16,13 +16,13 @@ var FileList={
$fileList.trigger(jQuery.Event("fileActionsReady"));
FileList.postProcessList();
// "Files" might not be loaded in extending apps
if (window.Files){
if (window.Files) {
Files.setupDragAndDrop();
}
FileList.updateFileSummary();
$fileList.trigger(jQuery.Event("updated"));
},
createRow:function(type, name, iconurl, linktarget, size, lastModified, permissions){
createRow:function(type, name, iconurl, linktarget, size, lastModified, permissions) {
var td, simpleSize, basename, extension;
//containing tr
var tr = $('<tr></tr>').attr({
@ -43,7 +43,7 @@ var FileList={
"href": linktarget
});
//split extension from filename for non dirs
if (type != 'dir' && name.indexOf('.')!=-1) {
if (type !== 'dir' && name.indexOf('.') !== -1) {
basename=name.substr(0,name.lastIndexOf('.'));
extension=name.substr(name.lastIndexOf('.'));
} else {
@ -52,11 +52,11 @@ var FileList={
}
var name_span=$('<span></span>').addClass('nametext').text(basename);
link_elem.append(name_span);
if(extension){
if (extension) {
name_span.append($('<span></span>').addClass('extension').text(extension));
}
//dirs can show the number of uploaded files
if (type == 'dir') {
if (type === 'dir') {
link_elem.append($('<span></span>').attr({
'class': 'uploadtext',
'currentUploads': 0
@ -66,9 +66,9 @@ var FileList={
tr.append(td);
//size column
if(size!=t('files', 'Pending')){
if (size !== t('files', 'Pending')) {
simpleSize = humanFileSize(size);
}else{
} else {
simpleSize=t('files', 'Pending');
}
var sizeColor = Math.round(160-Math.pow((size/(1024*1024)),2));
@ -90,7 +90,7 @@ var FileList={
tr.append(td);
return tr;
},
addFile:function(name,size,lastModified,loading,hidden,param){
addFile:function(name, size, lastModified, loading, hidden, param) {
var imgurl;
if (!param) {
@ -120,9 +120,9 @@ var FileList={
);
FileList.insertElement(name, 'file', tr);
if(loading){
tr.data('loading',true);
}else{
if (loading) {
tr.data('loading', true);
} else {
tr.find('td.filename').draggable(dragOptions);
}
if (hidden) {
@ -130,7 +130,7 @@ var FileList={
}
return tr;
},
addDir:function(name,size,lastModified,hidden){
addDir:function(name, size, lastModified, hidden) {
var tr = this.createRow(
'dir',
@ -142,7 +142,7 @@ var FileList={
$('#permissions').val()
);
FileList.insertElement(name,'dir',tr);
FileList.insertElement(name, 'dir', tr);
var td = tr.find('td.filename');
td.draggable(dragOptions);
td.droppable(folderDropOptions);
@ -156,25 +156,26 @@ var FileList={
* @brief Changes the current directory and reload the file list.
* @param targetDir target directory (non URL encoded)
* @param changeUrl false if the URL must not be changed (defaults to true)
* @param {boolean} force set to true to force changing directory
*/
changeDirectory: function(targetDir, changeUrl, force){
changeDirectory: function(targetDir, changeUrl, force) {
var $dir = $('#dir'),
url,
currentDir = $dir.val() || '/';
targetDir = targetDir || '/';
if (!force && currentDir === targetDir){
if (!force && currentDir === targetDir) {
return;
}
FileList.setCurrentDir(targetDir, changeUrl);
FileList.reload();
},
linkTo: function(dir){
linkTo: function(dir) {
return OC.linkTo('files', 'index.php')+"?dir="+ encodeURIComponent(dir).replace(/%2F/g, '/');
},
setCurrentDir: function(targetDir, changeUrl){
setCurrentDir: function(targetDir, changeUrl) {
$('#dir').val(targetDir);
if (changeUrl !== false){
if (window.history.pushState && changeUrl !== false){
if (changeUrl !== false) {
if (window.history.pushState && changeUrl !== false) {
url = FileList.linkTo(targetDir);
window.history.pushState({dir: targetDir}, '', url);
}
@ -187,9 +188,9 @@ var FileList={
/**
* @brief Reloads the file list using ajax call
*/
reload: function(){
reload: function() {
FileList.showMask();
if (FileList._reloadCall){
if (FileList._reloadCall) {
FileList._reloadCall.abort();
}
FileList._reloadCall = $.ajax({
@ -198,7 +199,7 @@ var FileList={
dir : $('#dir').val(),
breadcrumb: true
},
error: function(result){
error: function(result) {
FileList.reloadCallback(result);
},
success: function(result) {
@ -206,7 +207,7 @@ var FileList={
}
});
},
reloadCallback: function(result){
reloadCallback: function(result) {
var $controls = $('#controls');
delete FileList._reloadCall;
@ -217,17 +218,17 @@ var FileList={
return;
}
if (result.status === 404){
if (result.status === 404) {
// go back home
FileList.changeDirectory('/');
return;
}
if (result.data.permissions){
if (result.data.permissions) {
FileList.setDirectoryPermissions(result.data.permissions);
}
if(typeof(result.data.breadcrumb) != 'undefined'){
if (typeof(result.data.breadcrumb) !== 'undefined') {
$controls.find('.crumb').remove();
$controls.prepend(result.data.breadcrumb);
@ -236,14 +237,14 @@ var FileList={
Files.resizeBreadcrumbs(width, true);
// in case svg is not supported by the browser we need to execute the fallback mechanism
if(!SVGSupport()) {
if (!SVGSupport()) {
replaceSVG();
}
}
FileList.update(result.data.files);
},
setDirectoryPermissions: function(permissions){
setDirectoryPermissions: function(permissions) {
var isCreatable = (permissions & OC.PERMISSION_CREATE) !== 0;
$('#permissions').val(permissions);
$('.creatable').toggleClass('hidden', !isCreatable);
@ -278,66 +279,68 @@ var FileList={
$('tr').filterAttr('data-file',name).find('td.filename').draggable('destroy');
$('tr').filterAttr('data-file',name).remove();
FileList.updateFileSummary();
if($('tr[data-file]').length==0){
if ( ! $('tr[data-file]').exists() ) {
$('#emptycontent').removeClass('hidden');
$('#filescontent th').addClass('hidden');
}
},
insertElement:function(name,type,element){
insertElement:function(name, type, element) {
//find the correct spot to insert the file or folder
var pos, fileElements=$('tr[data-file][data-type="'+type+'"]:visible');
if(name.localeCompare($(fileElements[0]).attr('data-file'))<0){
pos=-1;
}else if(name.localeCompare($(fileElements[fileElements.length-1]).attr('data-file'))>0){
pos=fileElements.length-1;
}else{
for(pos=0;pos<fileElements.length-1;pos++){
if(name.localeCompare($(fileElements[pos]).attr('data-file'))>0 && name.localeCompare($(fileElements[pos+1]).attr('data-file'))<0){
if (name.localeCompare($(fileElements[0]).attr('data-file')) < 0) {
pos = -1;
} else if (name.localeCompare($(fileElements[fileElements.length-1]).attr('data-file')) > 0) {
pos = fileElements.length - 1;
} else {
for(pos = 0; pos<fileElements.length-1; pos++) {
if (name.localeCompare($(fileElements[pos]).attr('data-file')) > 0
&& name.localeCompare($(fileElements[pos+1]).attr('data-file')) < 0)
{
break;
}
}
}
if(fileElements.length){
if(pos==-1){
if (fileElements.exists()) {
if (pos === -1) {
$(fileElements[0]).before(element);
}else{
} else {
$(fileElements[pos]).after(element);
}
}else if(type=='dir' && $('tr[data-file]').length>0){
} else if (type === 'dir' && $('tr[data-file]').exists()) {
$('tr[data-file]').first().before(element);
} else if(type=='file' && $('tr[data-file]').length>0) {
} else if (type === 'file' && $('tr[data-file]').exists()) {
$('tr[data-file]').last().before(element);
}else{
} else {
$('#fileList').append(element);
}
$('#emptycontent').addClass('hidden');
$('#filestable th').removeClass('hidden');
FileList.updateFileSummary();
},
loadingDone:function(name, id){
var mime, tr=$('tr').filterAttr('data-file',name);
tr.data('loading',false);
mime=tr.data('mime');
tr.attr('data-mime',mime);
if (id != null) {
loadingDone:function(name, id) {
var mime, tr = $('tr[data-file="'+name+'"]');
tr.data('loading', false);
mime = tr.data('mime');
tr.attr('data-mime', mime);
if (id) {
tr.attr('data-id', id);
}
var path = getPathForPreview(name);
lazyLoadPreview(path, mime, function(previewpath){
lazyLoadPreview(path, mime, function(previewpath) {
tr.find('td.filename').attr('style','background-image:url('+previewpath+')');
});
tr.find('td.filename').draggable(dragOptions);
},
isLoading:function(name){
return $('tr').filterAttr('data-file',name).data('loading');
isLoading:function(name) {
return $('tr[data-file="'+name+'"]').data('loading');
},
rename:function(name){
rename:function(oldname) {
var tr, td, input, form;
tr=$('tr').filterAttr('data-file',name);
tr = $('tr[data-file="'+oldname+'"]');
tr.data('renaming',true);
td=tr.children('td.filename');
input=$('<input type="text" class="filename"/>').val(name);
form=$('<form></form>');
td = tr.children('td.filename');
input = $('<input type="text" class="filename"/>').val(oldname);
form = $('<form></form>');
form.append(input);
td.children('a.name').hide();
td.append(form);
@ -347,18 +350,29 @@ var FileList={
if (len === -1) {
len = input.val().length;
}
input.selectRange(0,len);
input.selectRange(0, len);
form.submit(function(event){
var checkInput = function () {
var filename = input.val();
if (filename !== oldname) {
if (!Files.isFileNameValid(filename)) {
// Files.isFileNameValid(filename) throws an exception itself
} else if($('#dir').val() === '/' && filename === 'Shared') {
throw t('files','In the home folder \'Shared\' is a reserved filename');
} else if (FileList.inList(filename)) {
throw t('files', '{new_name} already exists', {new_name: filename});
}
}
return true;
};
form.submit(function(event) {
event.stopPropagation();
event.preventDefault();
var newname=input.val();
if (!Files.isFileNameValid(newname)) {
return false;
} else if (newname != name) {
if (FileList.checkName(name, newname, false)) {
newname = name;
} else {
try {
var newname = input.val();
if (newname !== oldname) {
checkInput();
// save background image, because it's replaced by a spinner while async request
var oldBackgroundImage = td.css('background-image');
// mark as loading
@ -368,16 +382,16 @@ var FileList={
data: {
dir : $('#dir').val(),
newname: newname,
file: name
file: oldname
},
success: function(result) {
if (!result || result.status === 'error') {
OC.Notification.show(result.data.message);
newname = name;
OC.dialogs.alert(result.data.message, t('core', 'Could not rename file'));
// revert changes
newname = oldname;
tr.attr('data-file', newname);
var path = td.children('a.name').attr('href');
td.children('a.name').attr('href', path.replace(encodeURIComponent(name), encodeURIComponent(newname)));
td.children('a.name').attr('href', path.replace(encodeURIComponent(oldname), encodeURIComponent(newname)));
if (newname.indexOf('.') > 0 && tr.data('type') !== 'dir') {
var basename=newname.substr(0,newname.lastIndexOf('.'));
} else {
@ -385,7 +399,7 @@ var FileList={
}
td.find('a.name span.nametext').text(basename);
if (newname.indexOf('.') > 0 && tr.data('type') !== 'dir') {
if (td.find('a.name span.extension').length === 0 ) {
if ( ! td.find('a.name span.extension').exists() ) {
td.find('a.name span.nametext').append('<span class="extension"></span>');
}
td.find('a.name span.extension').text(newname.substr(newname.lastIndexOf('.')));
@ -393,70 +407,76 @@ var FileList={
tr.find('.fileactions').effect('highlight', {}, 5000);
tr.effect('highlight', {}, 5000);
}
// reinsert row
tr.detach();
FileList.insertElement( tr.attr('data-file'), tr.attr('data-type'),tr );
// remove loading mark and recover old image
td.css('background-image', oldBackgroundImage);
}
});
}
}
tr.data('renaming',false);
tr.attr('data-file', newname);
var path = td.children('a.name').attr('href');
td.children('a.name').attr('href', path.replace(encodeURIComponent(name), encodeURIComponent(newname)));
if (newname.indexOf('.') > 0 && tr.data('type') != 'dir') {
var basename=newname.substr(0,newname.lastIndexOf('.'));
} else {
var basename=newname;
}
td.find('a.name span.nametext').text(basename);
if (newname.indexOf('.') > 0 && tr.data('type') != 'dir') {
if (td.find('a.name span.extension').length == 0 ) {
td.find('a.name span.nametext').append('<span class="extension"></span>');
input.tipsy('hide');
tr.data('renaming',false);
tr.attr('data-file', newname);
var path = td.children('a.name').attr('href');
// FIXME this will fail if the path contains the filename.
td.children('a.name').attr('href', path.replace(encodeURIComponent(oldname), encodeURIComponent(newname)));
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() ) {
td.find('a.name span.nametext').append('<span class="extension"></span>');
}
td.find('a.name span.extension').text(newname.substr(newname.lastIndexOf('.')));
}
td.find('a.name span.extension').text(newname.substr(newname.lastIndexOf('.')));
form.remove();
td.children('a.name').show();
} catch (error) {
input.attr('title', error);
input.tipsy({gravity: 'w', trigger: 'manual'});
input.tipsy('show');
input.addClass('error');
}
form.remove();
td.children('a.name').show();
return false;
});
input.keyup(function(event){
if (event.keyCode == 27) {
input.keyup(function(event) {
// verify filename on typing
try {
checkInput();
input.tipsy('hide');
input.removeClass('error');
} catch (error) {
input.attr('title', error);
input.tipsy({gravity: 'w', trigger: 'manual'});
input.tipsy('show');
input.addClass('error');
}
if (event.keyCode === 27) {
input.tipsy('hide');
tr.data('renaming',false);
form.remove();
td.children('a.name').show();
}
});
input.click(function(event){
input.click(function(event) {
event.stopPropagation();
event.preventDefault();
});
input.blur(function(){
input.blur(function() {
form.trigger('submit');
});
},
checkName:function(oldName, newName, isNewFile) {
if (isNewFile || $('tr').filterAttr('data-file', newName).length > 0) {
var html;
if(isNewFile){
html = t('files', '{new_name} already exists', {new_name: escapeHTML(newName)})+'<span class="replace">'+t('files', 'replace')+'</span><span class="suggest">'+t('files', 'suggest name')+'</span>&nbsp;<span class="cancel">'+t('files', 'cancel')+'</span>';
}else{
html = t('files', '{new_name} already exists', {new_name: escapeHTML(newName)})+'<span class="replace">'+t('files', 'replace')+'</span><span class="cancel">'+t('files', 'cancel')+'</span>';
}
html = $('<span>' + html + '</span>');
html.attr('data-oldName', oldName);
html.attr('data-newName', newName);
html.attr('data-isNewFile', isNewFile);
OC.Notification.showHtml(html);
return true;
} else {
return false;
}
inList:function(filename) {
return $('#fileList tr[data-file="'+filename+'"]').length;
},
replace:function(oldName, newName, isNewFile) {
// Finish any existing actions
$('tr').filterAttr('data-file', oldName).hide();
$('tr').filterAttr('data-file', newName).hide();
var tr = $('tr').filterAttr('data-file', oldName).clone();
$('tr[data-file="'+oldName+'"]').hide();
$('tr[data-file="'+newName+'"]').hide();
var tr = $('tr[data-file="'+oldName+'"]').clone();
tr.attr('data-replace', 'true');
tr.attr('data-file', newName);
var td = tr.children('td.filename');
@ -485,14 +505,14 @@ var FileList={
FileList.finishReplace();
};
if (!isNewFile) {
OC.Notification.showHtml(t('files', 'replaced {new_name} with {old_name}', {new_name: newName}, {old_name: oldName})+'<span class="undo">'+t('files', 'undo')+'</span>');
OC.Notification.showHtml(t('files', 'replaced {new_name} with {old_name}', {new_name: newName}, {old_name: oldName})+'<span class="undo">'+t('files', 'undo')+'</span>');
}
},
finishReplace:function() {
if (!FileList.replaceCanceled && FileList.replaceOldName && FileList.replaceNewName) {
$.ajax({url: OC.filePath('files', 'ajax', 'rename.php'), async: false, data: { dir: $('#dir').val(), newname: FileList.replaceNewName, file: FileList.replaceOldName }, success: function(result) {
if (result && result.status == 'success') {
$('tr').filterAttr('data-replace', 'true').removeAttr('data-replace');
if (result && result.status === 'success') {
$('tr[data-replace="true"').removeAttr('data-replace');
} else {
OC.dialogs.alert(result.data.message, 'Error moving file');
}
@ -503,12 +523,12 @@ var FileList={
}});
}
},
do_delete:function(files){
if(files.substr){
do_delete:function(files) {
if (files.substr) {
files=[files];
}
for (var i=0; i<files.length; i++) {
var deleteAction = $('tr').filterAttr('data-file',files[i]).children("td.date").children(".action.delete");
var deleteAction = $('tr[data-file="'+files[i]+'"]').children("td.date").children(".action.delete");
deleteAction.removeClass('delete-icon').addClass('progress-icon');
}
// Finish any existing actions
@ -519,10 +539,10 @@ var FileList={
var fileNames = JSON.stringify(files);
$.post(OC.filePath('files', 'ajax', 'delete.php'),
{dir:$('#dir').val(),files:fileNames},
function(result){
if (result.status == 'success') {
$.each(files,function(index,file){
var files = $('tr').filterAttr('data-file',file);
function(result) {
if (result.status === 'success') {
$.each(files,function(index,file) {
var files = $('tr[data-file="'+file+'"]');
files.remove();
files.find('input[type="checkbox"]').removeAttr('checked');
files.removeClass('selected');
@ -533,14 +553,14 @@ var FileList={
FileList.updateEmptyContent();
} else {
$.each(files,function(index,file) {
var deleteAction = $('tr').filterAttr('data-file',files[i]).children("td.date").children(".action.delete");
var deleteAction = $('tr[data-file="'+files[i]+'"]').children("td.date").children(".action.delete");
deleteAction.removeClass('progress-icon').addClass('delete-icon');
});
}
});
},
createFileSummary: function() {
if( $('#fileList tr').length > 0 ) {
if ( $('#fileList tr').exists() ) {
var totalDirs = 0;
var totalFiles = 0;
var totalSize = 0;
@ -562,7 +582,7 @@ var FileList={
var infoVars = {
dirs: '<span class="dirinfo">'+directoryInfo+'</span><span class="connector">',
files: '</span><span class="fileinfo">'+fileInfo+'</span>'
}
};
var info = t('files', '{dirs} and {files}', infoVars);
@ -644,17 +664,17 @@ var FileList={
}
}
},
updateEmptyContent: function(){
updateEmptyContent: function() {
var $fileList = $('#fileList');
var permissions = $('#permissions').val();
var isCreatable = (permissions & OC.PERMISSION_CREATE) !== 0;
$('#emptycontent').toggleClass('hidden', !isCreatable || $fileList.find('tr').length > 0);
$('#filestable th').toggleClass('hidden', $fileList.find('tr').length === 0);
$('#emptycontent').toggleClass('hidden', !isCreatable || $fileList.find('tr').exists());
$('#filestable th').toggleClass('hidden', $fileList.find('tr').exists() === false);
},
showMask: function(){
showMask: function() {
// in case one was shown before
var $mask = $('#content .mask');
if ($mask.length){
if ($mask.exists()) {
return;
}
@ -665,31 +685,31 @@ var FileList={
$('#content').append($mask);
// block UI, but only make visible in case loading takes longer
FileList._maskTimeout = window.setTimeout(function(){
FileList._maskTimeout = window.setTimeout(function() {
// reset opacity
$mask.removeClass('transparent');
}, 250);
},
hideMask: function(){
hideMask: function() {
var $mask = $('#content .mask').remove();
if (FileList._maskTimeout){
if (FileList._maskTimeout) {
window.clearTimeout(FileList._maskTimeout);
}
},
scrollTo:function(file) {
//scroll to and highlight preselected file
var scrolltorow = $('tr[data-file="'+file+'"]');
if (scrolltorow.length > 0) {
scrolltorow.addClass('searchresult');
$(window).scrollTop(scrolltorow.position().top);
var $scrolltorow = $('tr[data-file="'+file+'"]');
if ($scrolltorow.exists()) {
$scrolltorow.addClass('searchresult');
$(window).scrollTop($scrolltorow.position().top);
//remove highlight when hovered over
scrolltorow.one('hover', function(){
scrolltorow.removeClass('searchresult');
$scrolltorow.one('hover', function() {
$scrolltorow.removeClass('searchresult');
});
}
},
filter:function(query){
$('#fileList tr:not(.summary)').each(function(i,e){
filter:function(query) {
$('#fileList tr:not(.summary)').each(function(i,e) {
if ($(e).data('file').toLowerCase().indexOf(query.toLowerCase()) !== -1) {
$(e).addClass("searchresult");
} else {
@ -698,18 +718,18 @@ var FileList={
});
//do not use scrollto to prevent removing searchresult css class
var first = $('#fileList tr.searchresult').first();
if (first.length !== 0) {
if (first.exists()) {
$(window).scrollTop(first.position().top);
}
},
unfilter:function(){
$('#fileList tr.searchresult').each(function(i,e){
unfilter:function() {
$('#fileList tr.searchresult').each(function(i,e) {
$(e).removeClass("searchresult");
});
}
};
$(document).ready(function(){
$(document).ready(function() {
var isPublic = !!$('#isPublic').val();
// handle upload events
@ -719,16 +739,16 @@ $(document).ready(function(){
OC.Upload.log('filelist handle fileuploaddrop', e, data);
var dropTarget = $(e.originalEvent.target).closest('tr, .crumb');
if(dropTarget && (dropTarget.data('type') === 'dir' || dropTarget.hasClass('crumb'))) { // drag&drop upload to folder
if (dropTarget && (dropTarget.data('type') === 'dir' || dropTarget.hasClass('crumb'))) { // drag&drop upload to folder
// remember as context
data.context = dropTarget;
var dir = dropTarget.data('file');
// if from file list, need to prepend parent dir
if (dir){
if (dir) {
var parentDir = $('#dir').val() || '/';
if (parentDir[parentDir.length - 1] != '/'){
if (parentDir[parentDir.length - 1] !== '/') {
parentDir += '/';
}
dir = parentDir + dir;
@ -752,12 +772,12 @@ $(document).ready(function(){
OC.Upload.log('filelist handle fileuploadadd', e, data);
//finish delete if we are uploading a deleted file
if(FileList.deleteFiles && FileList.deleteFiles.indexOf(data.files[0].name)!==-1){
if (FileList.deleteFiles && FileList.deleteFiles.indexOf(data.files[0].name)!==-1) {
FileList.finishDelete(null, true); //delete file before continuing
}
// add ui visualization to existing folder
if(data.context && data.context.data('type') === 'dir') {
if (data.context && data.context.data('type') === 'dir') {
// add to existing folder
// update upload counter ui
@ -767,7 +787,7 @@ $(document).ready(function(){
uploadtext.attr('currentUploads', currentUploads);
var translatedText = n('files', 'Uploading %n file', 'Uploading %n files', currentUploads);
if(currentUploads === 1) {
if (currentUploads === 1) {
var img = OC.imagePath('core', 'loading.gif');
data.context.find('td.filename').attr('style','background-image:url('+img+')');
uploadtext.text(translatedText);
@ -794,7 +814,7 @@ $(document).ready(function(){
}
var result=$.parseJSON(response);
if(typeof result[0] !== 'undefined' && result[0].status === 'success') {
if (typeof result[0] !== 'undefined' && result[0].status === 'success') {
var file = result[0];
if (data.context && data.context.data('type') === 'dir') {
@ -805,7 +825,7 @@ $(document).ready(function(){
currentUploads -= 1;
uploadtext.attr('currentUploads', currentUploads);
var translatedText = n('files', 'Uploading %n file', 'Uploading %n files', currentUploads);
if(currentUploads === 0) {
if (currentUploads === 0) {
var img = OC.imagePath('core', 'filetypes/folder.png');
data.context.find('td.filename').attr('style','background-image:url('+img+')');
uploadtext.text(translatedText);
@ -822,18 +842,18 @@ $(document).ready(function(){
} else {
// only append new file if dragged onto current dir's crumb (last)
if (data.context && data.context.hasClass('crumb') && !data.context.hasClass('last')){
if (data.context && data.context.hasClass('crumb') && !data.context.hasClass('last')) {
return;
}
// add as stand-alone row to filelist
var size=t('files', 'Pending');
if (data.files[0].size>=0){
if (data.files[0].size>=0) {
size=data.files[0].size;
}
var date=new Date();
var param = {};
if ($('#publicUploadRequestToken').length) {
if ($('#publicUploadRequestToken').exists()) {
param.download_url = document.location.href + '&download&path=/' + $('#dir').val() + '/' + file.name;
}
//should the file exist in the list remove it
@ -846,14 +866,14 @@ $(document).ready(function(){
data.context.attr('data-mime',file.mime).attr('data-id',file.id);
var permissions = data.context.data('permissions');
if(permissions !== file.permissions) {
if (permissions !== file.permissions) {
data.context.attr('data-permissions', file.permissions);
data.context.data('permissions', file.permissions);
}
FileActions.display(data.context.find('td.filename'), true);
var path = getPathForPreview(file.name);
lazyLoadPreview(path, file.mime, function(previewpath){
lazyLoadPreview(path, file.mime, function(previewpath) {
data.context.find('td.filename').attr('style','background-image:url('+previewpath+')');
});
}
@ -887,10 +907,10 @@ $(document).ready(function(){
});
$('#notification').hide();
$('#notification').on('click', '.undo', function(){
$('#notification').on('click', '.undo', function() {
if (FileList.deleteFiles) {
$.each(FileList.deleteFiles,function(index,file){
$('tr').filterAttr('data-file',file).show();
$.each(FileList.deleteFiles,function(index,file) {
$('tr[data-file="'+file+'"]').show();
});
FileList.deleteCanceled=true;
FileList.deleteFiles=null;
@ -900,10 +920,10 @@ $(document).ready(function(){
FileList.deleteCanceled = false;
FileList.deleteFiles = [FileList.replaceOldName];
} else {
$('tr').filterAttr('data-file', FileList.replaceOldName).show();
$('tr[data-file="'+FileList.replaceOldName+'"]').show();
}
$('tr').filterAttr('data-replace', 'true').remove();
$('tr').filterAttr('data-file', FileList.replaceNewName).show();
$('tr[data-replace="true"').remove();
$('tr[data-file="'+FileList.replaceNewName+'"]').show();
FileList.replaceCanceled = true;
FileList.replaceOldName = null;
FileList.replaceNewName = null;
@ -918,7 +938,7 @@ $(document).ready(function(){
});
});
$('#notification:first-child').on('click', '.suggest', function() {
$('tr').filterAttr('data-file', $('#notification > span').attr('data-oldName')).show();
$('tr[data-file="'+$('#notification > span').attr('data-oldName')+'"]').show();
OC.Notification.hide();
});
$('#notification:first-child').on('click', '.cancel', function() {
@ -928,67 +948,67 @@ $(document).ready(function(){
}
});
FileList.useUndo=(window.onbeforeunload)?true:false;
$(window).bind('beforeunload', function (){
$(window).bind('beforeunload', function () {
if (FileList.lastAction) {
FileList.lastAction();
}
});
$(window).unload(function (){
$(window).unload(function () {
$(window).trigger('beforeunload');
});
function decodeQuery(query){
function decodeQuery(query) {
return query.replace(/\+/g, ' ');
}
function parseHashQuery(){
function parseHashQuery() {
var hash = window.location.hash,
pos = hash.indexOf('?'),
query;
if (pos >= 0){
if (pos >= 0) {
return hash.substr(pos + 1);
}
return '';
}
function parseCurrentDirFromUrl(){
function parseCurrentDirFromUrl() {
var query = parseHashQuery(),
params,
dir = '/';
// try and parse from URL hash first
if (query){
if (query) {
params = OC.parseQueryString(decodeQuery(query));
}
// else read from query attributes
if (!params){
if (!params) {
params = OC.parseQueryString(decodeQuery(location.search));
}
return (params && params.dir) || '/';
}
// disable ajax/history API for public app (TODO: until it gets ported)
if (!isPublic){
if (!isPublic) {
// fallback to hashchange when no history support
if (!window.history.pushState){
$(window).on('hashchange', function(){
if (!window.history.pushState) {
$(window).on('hashchange', function() {
FileList.changeDirectory(parseCurrentDirFromUrl(), false);
});
}
window.onpopstate = function(e){
window.onpopstate = function(e) {
var targetDir;
if (e.state && e.state.dir){
if (e.state && e.state.dir) {
targetDir = e.state.dir;
}
else{
// read from URL
targetDir = parseCurrentDirFromUrl();
}
if (targetDir){
if (targetDir) {
FileList.changeDirectory(targetDir, false);
}
}
};
if (parseInt($('#ajaxLoad').val(), 10) === 1){
if (parseInt($('#ajaxLoad').val(), 10) === 1) {
// need to initially switch the dir to the one from the hash (IE8)
FileList.changeDirectory(parseCurrentDirFromUrl(), false, true);
}

View File

@ -1,18 +1,18 @@
Files={
updateMaxUploadFilesize:function(response) {
if(response == undefined) {
if (response === undefined) {
return;
}
if(response.data !== undefined && response.data.uploadMaxFilesize !== undefined) {
if (response.data !== undefined && response.data.uploadMaxFilesize !== undefined) {
$('#max_upload').val(response.data.uploadMaxFilesize);
$('#upload.button').attr('original-title', response.data.maxHumanFilesize);
$('#usedSpacePercent').val(response.data.usedSpacePercent);
Files.displayStorageWarnings();
}
if(response[0] == undefined) {
if (response[0] === undefined) {
return;
}
if(response[0].uploadMaxFilesize !== undefined) {
if (response[0].uploadMaxFilesize !== undefined) {
$('#max_upload').val(response[0].uploadMaxFilesize);
$('#upload.button').attr('original-title', response[0].maxHumanFilesize);
$('#usedSpacePercent').val(response[0].usedSpacePercent);
@ -22,23 +22,18 @@ Files={
},
isFileNameValid:function (name) {
if (name === '.') {
OC.Notification.show(t('files', '\'.\' is an invalid file name.'));
return false;
}
if (name.length == 0) {
OC.Notification.show(t('files', 'File name cannot be empty.'));
return false;
throw t('files', '\'.\' is an invalid file name.');
} else if (name.length === 0) {
throw t('files', 'File name cannot be empty.');
}
// check for invalid characters
var invalid_characters = ['\\', '/', '<', '>', ':', '"', '|', '?', '*'];
for (var i = 0; i < invalid_characters.length; i++) {
if (name.indexOf(invalid_characters[i]) != -1) {
OC.Notification.show(t('files', "Invalid name, '\\', '/', '<', '>', ':', '\"', '|', '?' and '*' are not allowed."));
return false;
if (name.indexOf(invalid_characters[i]) !== -1) {
throw t('files', "Invalid name, '\\', '/', '<', '>', ':', '\"', '|', '?' and '*' are not allowed.");
}
}
OC.Notification.hide();
return true;
},
displayStorageWarnings: function() {
@ -78,18 +73,18 @@ Files={
}
},
setupDragAndDrop: function(){
setupDragAndDrop: function() {
var $fileList = $('#fileList');
//drag/drop of files
$fileList.find('tr td.filename').each(function(i,e){
$fileList.find('tr td.filename').each(function(i,e) {
if ($(e).parent().data('permissions') & OC.PERMISSION_DELETE) {
$(e).draggable(dragOptions);
}
});
$fileList.find('tr[data-type="dir"] td.filename').each(function(i,e){
if ($(e).parent().data('permissions') & OC.PERMISSION_CREATE){
$fileList.find('tr[data-type="dir"] td.filename').each(function(i,e) {
if ($(e).parent().data('permissions') & OC.PERMISSION_CREATE) {
$(e).droppable(folderDropOptions);
}
});
@ -127,9 +122,9 @@ Files={
},
resizeBreadcrumbs: function (width, firstRun) {
if (width != Files.lastWidth) {
if (width !== Files.lastWidth) {
if ((width < Files.lastWidth || firstRun) && width < Files.breadcrumbsWidth) {
if (Files.hiddenBreadcrumbs == 0) {
if (Files.hiddenBreadcrumbs === 0) {
Files.breadcrumbsWidth -= $(Files.breadcrumbs[1]).get(0).offsetWidth;
$(Files.breadcrumbs[1]).find('a').hide();
$(Files.breadcrumbs[1]).append('<span>...</span>');
@ -141,12 +136,12 @@ Files={
Files.breadcrumbsWidth -= $(Files.breadcrumbs[i]).get(0).offsetWidth;
$(Files.breadcrumbs[i]).hide();
Files.hiddenBreadcrumbs = i;
i++
i++;
}
} else if (width > Files.lastWidth && Files.hiddenBreadcrumbs > 0) {
var i = Files.hiddenBreadcrumbs;
while (width > Files.breadcrumbsWidth && i > 0) {
if (Files.hiddenBreadcrumbs == 1) {
if (Files.hiddenBreadcrumbs === 1) {
Files.breadcrumbsWidth -= $(Files.breadcrumbs[1]).get(0).offsetWidth;
$(Files.breadcrumbs[1]).find('span').remove();
$(Files.breadcrumbs[1]).find('a').show();
@ -170,7 +165,7 @@ Files={
};
$(document).ready(function() {
// FIXME: workaround for trashbin app
if (window.trashBinApp){
if (window.trashBinApp) {
return;
}
Files.displayEncryptionWarning();
@ -215,7 +210,7 @@ $(document).ready(function() {
var rows = $(this).parent().parent().parent().children('tr');
for (var i = start; i < end; i++) {
$(rows).each(function(index) {
if (index == i) {
if (index === i) {
var checkbox = $(this).children().children('input:checkbox');
$(checkbox).attr('checked', 'checked');
$(checkbox).parent().parent().addClass('selected');
@ -232,23 +227,23 @@ $(document).ready(function() {
} else {
$(checkbox).attr('checked', 'checked');
$(checkbox).parent().parent().toggleClass('selected');
var selectedCount=$('td.filename input:checkbox:checked').length;
if (selectedCount == $('td.filename input:checkbox').length) {
var selectedCount = $('td.filename input:checkbox:checked').length;
if (selectedCount === $('td.filename input:checkbox').length) {
$('#select_all').attr('checked', 'checked');
}
}
procesSelection();
} else {
var filename=$(this).parent().parent().attr('data-file');
var tr=$('tr').filterAttr('data-file',filename);
var tr=$('tr[data-file="'+filename+'"]');
var renaming=tr.data('renaming');
if(!renaming && !FileList.isLoading(filename)){
if (!renaming && !FileList.isLoading(filename)) {
FileActions.currentFile = $(this).parent();
var mime=FileActions.getCurrentMimeType();
var type=FileActions.getCurrentType();
var permissions = FileActions.getCurrentPermissions();
var action=FileActions.getDefault(mime,type, permissions);
if(action){
if (action) {
event.preventDefault();
action(filename);
}
@ -259,11 +254,11 @@ $(document).ready(function() {
// Sets the select_all checkbox behaviour :
$('#select_all').click(function() {
if($(this).attr('checked')){
if ($(this).attr('checked')) {
// Check all
$('td.filename input:checkbox').attr('checked', true);
$('td.filename input:checkbox').parent().parent().addClass('selected');
}else{
} else {
// Uncheck all
$('td.filename input:checkbox').attr('checked', false);
$('td.filename input:checkbox').parent().parent().removeClass('selected');
@ -280,7 +275,7 @@ $(document).ready(function() {
var rows = $(this).parent().parent().parent().children('tr');
for (var i = start; i < end; i++) {
$(rows).each(function(index) {
if (index == i) {
if (index === i) {
var checkbox = $(this).children().children('input:checkbox');
$(checkbox).attr('checked', 'checked');
$(checkbox).parent().parent().addClass('selected');
@ -290,10 +285,10 @@ $(document).ready(function() {
}
var selectedCount=$('td.filename input:checkbox:checked').length;
$(this).parent().parent().toggleClass('selected');
if(!$(this).attr('checked')){
if (!$(this).attr('checked')) {
$('#select_all').attr('checked',false);
}else{
if(selectedCount==$('td.filename input:checkbox').length){
} else {
if (selectedCount===$('td.filename input:checkbox').length) {
$('#select_all').attr('checked',true);
}
}
@ -306,10 +301,11 @@ $(document).ready(function() {
var dir=$('#dir').val()||'/';
OC.Notification.show(t('files','Your download is being prepared. This might take some time if the files are big.'));
// use special download URL if provided, e.g. for public shared files
if ( (downloadURL = document.getElementById("downloadURL")) ) {
window.location=downloadURL.value+"&download&files="+encodeURIComponent(fileslist);
var downloadURL = document.getElementById("downloadURL");
if ( downloadURL ) {
window.location = downloadURL.value+"&download&files=" + encodeURIComponent(fileslist);
} else {
window.location=OC.filePath('files', 'ajax', 'download.php') + '?'+ $.param({ dir: dir, files: fileslist });
window.location = OC.filePath('files', 'ajax', 'download.php') + '?'+ $.param({ dir: dir, files: fileslist });
}
return false;
});
@ -376,12 +372,12 @@ $(document).ready(function() {
}
});
function scanFiles(force, dir, users){
function scanFiles(force, dir, users) {
if (!OC.currentUser) {
return;
}
if(!dir){
if (!dir) {
dir = '';
}
force = !!force; //cast to bool
@ -399,17 +395,17 @@ function scanFiles(force, dir, users){
scannerEventSource = new OC.EventSource(OC.filePath('files','ajax','scan.php'),{force: force,dir: dir});
}
scanFiles.cancel = scannerEventSource.close.bind(scannerEventSource);
scannerEventSource.listen('count',function(count){
console.log(count + ' files scanned')
scannerEventSource.listen('count',function(count) {
console.log(count + ' files scanned');
});
scannerEventSource.listen('folder',function(path){
console.log('now scanning ' + path)
scannerEventSource.listen('folder',function(path) {
console.log('now scanning ' + path);
});
scannerEventSource.listen('done',function(count){
scannerEventSource.listen('done',function(count) {
scanFiles.scanning=false;
console.log('done after ' + count + ' files');
});
scannerEventSource.listen('user',function(user){
scannerEventSource.listen('user',function(user) {
console.log('scanning files for ' + user);
});
}
@ -418,14 +414,14 @@ scanFiles.scanning=false;
function boolOperationFinished(data, callback) {
result = jQuery.parseJSON(data.responseText);
Files.updateMaxUploadFilesize(result);
if(result.status == 'success'){
if (result.status === 'success') {
callback.call();
} else {
alert(result.data.message);
}
}
var createDragShadow = function(event){
var createDragShadow = function(event) {
//select dragged file
var isDragSelected = $(event.target).parents('tr').find('td input:first').prop('checked');
if (!isDragSelected) {
@ -435,7 +431,7 @@ var createDragShadow = function(event){
var selectedFiles = getSelectedFilesTrash();
if (!isDragSelected && selectedFiles.length == 1) {
if (!isDragSelected && selectedFiles.length === 1) {
//revert the selection
$(event.target).parents('tr').find('td input:first').prop('checked',false);
}
@ -452,7 +448,7 @@ var createDragShadow = function(event){
var dir=$('#dir').val();
$(selectedFiles).each(function(i,elem){
$(selectedFiles).each(function(i,elem) {
var newtr = $('<tr/>').attr('data-dir', dir).attr('data-filename', elem.name);
newtr.append($('<td/>').addClass('filename').text(elem.name));
newtr.append($('<td/>').addClass('size').text(humanFileSize(elem.size)));
@ -461,14 +457,14 @@ var createDragShadow = function(event){
newtr.find('td.filename').attr('style','background-image:url('+OC.imagePath('core', 'filetypes/folder.png')+')');
} else {
var path = getPathForPreview(elem.name);
lazyLoadPreview(path, elem.mime, function(previewpath){
lazyLoadPreview(path, elem.mime, function(previewpath) {
newtr.find('td.filename').attr('style','background-image:url('+previewpath+')');
});
}
});
return dragshadow;
}
};
//options for file drag/drop
var dragOptions={
@ -478,7 +474,7 @@ var dragOptions={
stop: function(event, ui) {
$('#fileList tr td.filename').addClass('ui-draggable');
}
}
};
// sane browsers support using the distance option
if ( $('html.ie').length === 0) {
dragOptions['distance'] = 20;
@ -491,20 +487,20 @@ var folderDropOptions={
return false;
}
var target=$.trim($(this).find('.nametext').text());
var target = $.trim($(this).find('.nametext').text());
var files = ui.helper.find('tr');
$(files).each(function(i,row){
$(files).each(function(i,row) {
var dir = $(row).data('dir');
var file = $(row).data('filename');
$.post(OC.filePath('files', 'ajax', 'move.php'), { dir: dir, file: file, target: dir+'/'+target }, function(result) {
if (result) {
if (result.status === 'success') {
//recalculate folder size
var oldSize = $('#fileList tr').filterAttr('data-file',target).data('size');
var newSize = oldSize + $('#fileList tr').filterAttr('data-file',file).data('size');
$('#fileList tr').filterAttr('data-file',target).data('size', newSize);
$('#fileList tr').filterAttr('data-file',target).find('td.filesize').text(humanFileSize(newSize));
var oldSize = $('#fileList tr[data-file="'+target+'"]').data('size');
var newSize = oldSize + $('#fileList tr[data-file="'+file+'"]').data('size');
$('#fileList tr[data-file="'+target+'"]').data('size', newSize);
$('#fileList tr[data-file="'+target+'"]').find('td.filesize').text(humanFileSize(newSize));
FileList.remove(file);
procesSelection();
@ -521,24 +517,24 @@ var folderDropOptions={
});
},
tolerance: 'pointer'
}
};
var crumbDropOptions={
drop: function( event, ui ) {
var target=$(this).data('dir');
var dir=$('#dir').val();
while(dir.substr(0,1)=='/'){//remove extra leading /'s
var dir = $('#dir').val();
while(dir.substr(0,1) === '/') {//remove extra leading /'s
dir=dir.substr(1);
}
dir='/'+dir;
if(dir.substr(-1,1)!='/'){
dir=dir+'/';
dir = '/' + dir;
if (dir.substr(-1,1) !== '/') {
dir = dir + '/';
}
if(target==dir || target+'/'==dir){
if (target === dir || target+'/' === dir) {
return;
}
var files = ui.helper.find('tr');
$(files).each(function(i,row){
$(files).each(function(i,row) {
var dir = $(row).data('dir');
var file = $(row).data('filename');
$.post(OC.filePath('files', 'ajax', 'move.php'), { dir: dir, file: file, target: target }, function(result) {
@ -559,13 +555,17 @@ var crumbDropOptions={
});
},
tolerance: 'pointer'
}
};
function procesSelection(){
var selected=getSelectedFilesTrash();
var selectedFiles=selected.filter(function(el){return el.type=='file'});
var selectedFolders=selected.filter(function(el){return el.type=='dir'});
if(selectedFiles.length==0 && selectedFolders.length==0) {
function procesSelection() {
var selected = getSelectedFilesTrash();
var selectedFiles = selected.filter(function(el) {
return el.type==='file';
});
var selectedFolders = selected.filter(function(el) {
return el.type==='dir';
});
if (selectedFiles.length === 0 && selectedFolders.length === 0) {
$('#headerName>span.name').text(t('files','Name'));
$('#headerSize').text(t('files','Size'));
$('#modified').text(t('files','Modified'));
@ -574,22 +574,22 @@ function procesSelection(){
}
else {
$('.selectedActions').show();
var totalSize=0;
for(var i=0;i<selectedFiles.length;i++){
var totalSize = 0;
for(var i=0; i<selectedFiles.length; i++) {
totalSize+=selectedFiles[i].size;
};
for(var i=0;i<selectedFolders.length;i++){
for(var i=0; i<selectedFolders.length; i++) {
totalSize+=selectedFolders[i].size;
};
$('#headerSize').text(humanFileSize(totalSize));
var selection='';
if(selectedFolders.length>0){
var selection = '';
if (selectedFolders.length > 0) {
selection += n('files', '%n folder', '%n folders', selectedFolders.length);
if(selectedFiles.length>0){
selection+=' & ';
if (selectedFiles.length > 0) {
selection += ' & ';
}
}
if(selectedFiles.length>0){
if (selectedFiles.length>0) {
selection += n('files', '%n file', '%n files', selectedFiles.length);
}
$('#headerName>span.name').text(selection);
@ -600,37 +600,37 @@ function procesSelection(){
/**
* @brief get a list of selected files
* @param string property (option) the property of the file requested
* @return array
* @param {string} property (option) the property of the file requested
* @return {array}
*
* possible values for property: name, mime, size and type
* if property is set, an array with that property for each file is returnd
* if it's ommited an array of objects with all properties is returned
*/
function getSelectedFilesTrash(property){
function getSelectedFilesTrash(property) {
var elements=$('td.filename input:checkbox:checked').parent().parent();
var files=[];
elements.each(function(i,element){
elements.each(function(i,element) {
var file={
name:$(element).attr('data-file'),
mime:$(element).data('mime'),
type:$(element).data('type'),
size:$(element).data('size')
};
if(property){
if (property) {
files.push(file[property]);
}else{
} else {
files.push(file);
}
});
return files;
}
function getMimeIcon(mime, ready){
if(getMimeIcon.cache[mime]){
function getMimeIcon(mime, ready) {
if (getMimeIcon.cache[mime]) {
ready(getMimeIcon.cache[mime]);
}else{
$.get( OC.filePath('files','ajax','mimeicon.php'), {mime: mime}, function(path){
} else {
$.get( OC.filePath('files','ajax','mimeicon.php'), {mime: mime}, function(path) {
getMimeIcon.cache[mime]=path;
ready(getMimeIcon.cache[mime]);
});
@ -655,7 +655,7 @@ function lazyLoadPreview(path, mime, ready, width, height) {
if ( ! height ) {
height = $('#filestable').data('preview-y');
}
if( $('#publicUploadButtonMock').length ) {
if ( $('#publicUploadButtonMock').length ) {
var previewURL = OC.Router.generate('core_ajax_public_preview', {file: path, x:width, y:height, t:$('#dirToken').val()});
} else {
var previewURL = OC.Router.generate('core_ajax_preview', {file: path, x:width, y:height});
@ -677,8 +677,8 @@ function lazyLoadPreview(path, mime, ready, width, height) {
});
}
function getUniqueName(name){
if($('tr').filterAttr('data-file',name).length>0){
function getUniqueName(name) {
if ($('tr[data-file="'+name+'"]').exists()) {
var parts=name.split('.');
var extension = "";
if (parts.length > 1) {
@ -687,9 +687,9 @@ function getUniqueName(name){
var base=parts.join('.');
numMatch=base.match(/\((\d+)\)/);
var num=2;
if(numMatch && numMatch.length>0){
if (numMatch && numMatch.length>0) {
num=parseInt(numMatch[numMatch.length-1])+1;
base=base.split('(')
base=base.split('(');
base.pop();
base=$.trim(base.join('('));
}
@ -703,19 +703,19 @@ function getUniqueName(name){
}
function checkTrashStatus() {
$.post(OC.filePath('files_trashbin', 'ajax', 'isEmpty.php'), function(result){
$.post(OC.filePath('files_trashbin', 'ajax', 'isEmpty.php'), function(result) {
if (result.data.isEmpty === false) {
$("input[type=button][id=trash]").removeAttr("disabled");
}
});
}
function onClickBreadcrumb(e){
function onClickBreadcrumb(e) {
var $el = $(e.target).closest('.crumb'),
$targetDir = $el.data('dir');
isPublic = !!$('#isPublic').val();
if ($targetDir !== undefined && !isPublic){
if ($targetDir !== undefined && !isPublic) {
e.preventDefault();
FileList.changeDirectory(decodeURIComponent($targetDir));
}

View File

@ -25,7 +25,14 @@
namespace OCA\Files;
class App {
/**
* @var \OC_L10N
*/
private $l10n;
/**
* @var \OC\Files\View
*/
private $view;
public function __construct($view, $l10n) {
@ -52,7 +59,15 @@ class App {
$result['data'] = array(
'message' => $this->l10n->t("Invalid folder name. Usage of 'Shared' is reserved by ownCloud")
);
} elseif(
// rename to existing file is denied
} else if ($this->view->file_exists($dir . '/' . $newname)) {
$result['data'] = array(
'message' => $this->l10n->t(
"The name %s is already used in the folder %s. Please choose a different name.",
array($newname, $dir))
);
} else if (
// rename to "." is denied
$newname !== '.' and
// rename of "/Shared" is denied

View File

@ -37,7 +37,7 @@
</div>
<div id="file_action_panel"></div>
<div class="notCreatable notPublic <?php if ($_['isCreatable'] or $_['isPublic'] ):?>hidden<?php endif; ?>">
<div class="actions"><input type="button" disabled value="<?php p($l->t('You dont have write permissions here.'))?>"></div>
<?php p($l->t('You dont have permission to upload or create files here'))?>
</div>
<input type="hidden" name="permissions" value="<?php p($_['permissions']); ?>" id="permissions">
</div>

View File

@ -508,11 +508,18 @@ class Util {
) {
// get the size from filesystem
$fullPath = $this->view->getLocalFile($path);
$size = $this->view->filesize($path);
// fast path, else the calculation for $lastChunkNr is bogus
if ($size === 0) {
\OC_FileProxy::$enabled = $proxyStatus;
return 0;
}
// calculate last chunk nr
$lastChunkNr = floor($size / 8192);
// next highest is end of chunks, one subtracted is last one
// we have to read the last chunk, we can't just calculate it (because of padding etc)
$lastChunkNr = ceil($size/ 8192) - 1;
$lastChunkSize = $size - ($lastChunkNr * 8192);
// open stream

View File

@ -241,6 +241,34 @@ class Test_Encryption_Util extends \PHPUnit_Framework_TestCase {
$this->view->unlink($this->userId . '/files/' . $filename);
}
/**
< * @brief Test that data that is read by the crypto stream wrapper
*/
function testGetFileSize() {
\Test_Encryption_Util::loginHelper(\Test_Encryption_Util::TEST_ENCRYPTION_UTIL_USER1);
$filename = 'tmp-' . time();
$externalFilename = '/' . $this->userId . '/files/' . $filename;
// Test for 0 byte files
$problematicFileSizeData = "";
$cryptedFile = $this->view->file_put_contents($externalFilename, $problematicFileSizeData);
$this->assertTrue(is_int($cryptedFile));
$this->assertEquals($this->util->getFileSize($externalFilename), 0);
$decrypt = $this->view->file_get_contents($externalFilename);
$this->assertEquals($problematicFileSizeData, $decrypt);
$this->view->unlink($this->userId . '/files/' . $filename);
// Test a file with 18377 bytes as in https://github.com/owncloud/mirall/issues/1009
$problematicFileSizeData = str_pad("", 18377, "abc");
$cryptedFile = $this->view->file_put_contents($externalFilename, $problematicFileSizeData);
$this->assertTrue(is_int($cryptedFile));
$this->assertEquals($this->util->getFileSize($externalFilename), 18377);
$decrypt = $this->view->file_get_contents($externalFilename);
$this->assertEquals($problematicFileSizeData, $decrypt);
$this->view->unlink($this->userId . '/files/' . $filename);
}
/**
* @medium
*/
@ -333,7 +361,7 @@ class Test_Encryption_Util extends \PHPUnit_Framework_TestCase {
/**
* helper function to set migration status to the right value
* to be able to test the migration path
*
*
* @param $status needed migration status for test
* @param $user for which user the status should be set
* @return boolean

View File

@ -32,17 +32,19 @@ class Shared_Updater {
$uid = \OCP\User::getUser();
$uidOwner = \OC\Files\Filesystem::getOwner($target);
$info = \OC\Files\Filesystem::getFileInfo($target);
$checkedUser = array($uidOwner);
// Correct Shared folders of other users shared with
$users = \OCP\Share::getUsersItemShared('file', $info['fileid'], $uidOwner, true);
if (!empty($users)) {
while (!empty($users)) {
$reshareUsers = array();
foreach ($users as $user) {
if ( $user !== $uidOwner ) {
if ( !in_array($user, $checkedUser) ) {
$etag = \OC\Files\Filesystem::getETag('');
\OCP\Config::setUserValue($user, 'files_sharing', 'etag', $etag);
// Look for reshares
$reshareUsers = array_merge($reshareUsers, \OCP\Share::getUsersItemShared('file', $info['fileid'], $user, true));
$checkedUser[] = $user;
}
}
$users = $reshareUsers;

View File

@ -0,0 +1,96 @@
<?php
/**
* ownCloud - user_ldap
*
* @author Arthur Schiwon
* @copyright 2013 Arthur Schiwon blizzz@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/>.
*
*/
// Check user and app status
OCP\JSON::checkAdminUser();
OCP\JSON::checkAppEnabled('user_ldap');
OCP\JSON::callCheck();
$l=OC_L10N::get('user_ldap');
if(!isset($_POST['action'])) {
\OCP\JSON::error(array('message' => $l->t('No action specified')));
}
$action = $_POST['action'];
if(!isset($_POST['ldap_serverconfig_chooser'])) {
\OCP\JSON::error(array('message' => $l->t('No configuration specified')));
}
$prefix = $_POST['ldap_serverconfig_chooser'];
$ldapWrapper = new OCA\user_ldap\lib\LDAP();
$configuration = new \OCA\user_ldap\lib\Configuration($prefix);
$wizard = new \OCA\user_ldap\lib\Wizard($configuration, $ldapWrapper);
switch($action) {
case 'guessPortAndTLS':
case 'guessBaseDN':
case 'determineGroupMemberAssoc':
case 'determineUserObjectClasses':
case 'determineGroupObjectClasses':
case 'determineGroupsForUsers':
case 'determineGroupsForGroups':
case 'determineAttributes':
case 'getUserListFilter':
case 'getUserLoginFilter':
case 'getGroupFilter':
case 'countUsers':
case 'countGroups':
try {
$result = $wizard->$action();
if($result !== false) {
OCP\JSON::success($result->getResultArray());
exit;
}
} catch (\Exception $e) {
\OCP\JSON::error(array('message' => $e->getMessage()));
exit;
}
\OCP\JSON::error();
exit;
break;
case 'save':
$key = isset($_POST['cfgkey']) ? $_POST['cfgkey'] : false;
$val = isset($_POST['cfgval']) ? $_POST['cfgval'] : null;
if($key === false || is_null($val)) {
\OCP\JSON::error(array('message' => $l->t('No data specified')));
exit;
}
$cfg = array($key => $val);
$setParameters = array();
$configuration->setConfiguration($cfg, $setParameters);
if(!in_array($key, $setParameters)) {
\OCP\JSON::error(array('message' => $l->t($key.
' Could not set configuration %s', $setParameters[0])));
exit;
}
$configuration->saveConfiguration();
OCP\JSON::success();
break;
default:
//TODO: return 4xx error
break;
}

View File

@ -30,7 +30,7 @@ if(count($configPrefixes) === 1) {
$ldapAccess = new OCA\user_ldap\lib\Access($connector, $ldapWrapper);
$userBackend = new OCA\user_ldap\USER_LDAP($ldapAccess);
$groupBackend = new OCA\user_ldap\GROUP_LDAP($ldapAccess);
} else {
} else if(count($configPrefixes) > 1) {
$userBackend = new OCA\user_ldap\User_Proxy($configPrefixes, $ldapWrapper);
$groupBackend = new OCA\user_ldap\Group_Proxy($configPrefixes, $ldapWrapper);
}

View File

@ -1,3 +1,85 @@
.table {
display: table;
width: 60%;
}
.tablecell {
display: table-cell !important;
white-space: nowrap;
}
.tablerow {
display: table-row;
}
.tablerow input, .tablerow textarea {
width: 100% !important;
}
.tablerow textarea {
height: 15px;
}
.invisible {
visibility: hidden;
}
.ldapSettingsTabs {
float: right !important;
}
.ldapWizardControls {
width: 60%;
text-align: right;
}
.ldapWizardInfo {
width: 100% !important;
height: 50px;
background-color: lightyellow;
border-radius: 0.5em;
padding: 0.6em 0.5em 0.4em !important;
margin-bottom: 0.3em;
}
#ldapWizard1 .hostPortCombinator {
width: 60%;
display: table;
}
#ldapWizard1 .hostPortCombinator div span {
width: 7%;
display: table-cell;
text-align: right;
}
#ldapWizard1 .host {
width: 96.5% !important;
}
.tableCellInput {
margin-left: -40%;
width: 100%;
}
.tableCellLabel {
text-align: right;
padding-right: 25%;
}
.ldapIndent {
margin-left: 50px;
}
.ldapwarning {
margin-left: 1.4em;
color: #FF3B3B;
}
.wizSpinner {
height: 15px;
}
#ldap fieldset p label {
width: 20%;
max-width: 200px;
@ -9,7 +91,7 @@
}
#ldap fieldset input, #ldap fieldset textarea {
width: 60%;
width: 60%;
display: inline-block;
}
@ -17,11 +99,9 @@
vertical-align: bottom;
}
.ldapIndent {
margin-left: 50px;
}
.ldapwarning {
margin-left: 1.4em;
color: #FF3B3B;
}
select[multiple=multiple] + button {
height: 28px;
padding-top: 6px !important;
min-width: 40%;
max-width: 40%;
}

View File

@ -30,6 +30,7 @@ var LdapConfiguration = {
// assign the value
$('#'+configkey).val(configvalue);
});
LdapWizard.init();
}
}
);
@ -91,6 +92,7 @@ var LdapConfiguration = {
$('#ldap_serverconfig_chooser option:selected').removeAttr('selected');
var html = '<option value="'+result.configPrefix+'" selected="selected">'+$('#ldap_serverconfig_chooser option').length+'. Server</option>';
$('#ldap_serverconfig_chooser option:last').before(html);
LdapWizard.init();
} else {
OC.dialogs.alert(
result.message,
@ -122,13 +124,546 @@ var LdapConfiguration = {
}
};
var LdapWizard = {
checkPortInfoShown: false,
saveBlacklist: {},
userFilterGroupSelectState: 'enable',
spinner: '<img class="wizSpinner" src="'+ OC.imagePath('core', 'loading.gif') +'">',
ajax: function(param, fnOnSuccess, fnOnError) {
$.post(
OC.filePath('user_ldap','ajax','wizard.php'),
param,
function(result) {
if(result.status == 'success') {
fnOnSuccess(result);
} else {
fnOnError(result);
}
}
);
},
applyChanges: function (result) {
for (id in result.changes) {
if(!$.isArray(result.changes[id])) {
//no need to blacklist multiselect
LdapWizard.saveBlacklist[id] = true;
}
if(id.indexOf('count') > 0) {
$('#'+id).text(result.changes[id]);
} else {
$('#'+id).val(result.changes[id]);
}
}
LdapWizard.functionalityCheck();
if($('#ldapSettings').tabs('option', 'active') == 0) {
LdapWizard.basicStatusCheck();
}
},
basicStatusCheck: function() {
//criterias to continue from the first tab
// - host, port, user filter, agent dn, password, base dn
host = $('#ldap_host').val();
port = $('#ldap_port').val();
agent = $('#ldap_dn').val();
pwd = $('#ldap_agent_password').val();
base = $('#ldap_base').val();
if(host && port && agent && pwd && base) {
$('.ldap_action_continue').removeAttr('disabled');
$('#ldapSettings').tabs('option', 'disabled', []);
} else {
$('.ldap_action_continue').attr('disabled', 'disabled');
$('#ldapSettings').tabs('option', 'disabled', [1, 2, 3, 4, 5]);
}
},
checkBaseDN: function() {
host = $('#ldap_host').val();
port = $('#ldap_port').val();
user = $('#ldap_dn').val();
pass = $('#ldap_agent_password').val();
if(host && port && user && pass) {
param = 'action=guessBaseDN'+
'&ldap_serverconfig_chooser='+$('#ldap_serverconfig_chooser').val();
LdapWizard.showSpinner('#ldap_base');
LdapWizard.ajax(param,
function(result) {
LdapWizard.applyChanges(result);
LdapWizard.hideSpinner('#ldap_base');
if($('#ldap_base').val()) {
$('#ldap_base').removeClass('invisible');
LdapWizard.hideInfoBox();
}
},
function (result) {
LdapWizard.hideSpinner('#ldap_base');
$('#ldap_base').removeClass('invisible');
LdapWizard.showInfoBox('Please specify a port');
}
);
}
},
checkPort: function() {
host = $('#ldap_host').val();
user = $('#ldap_dn').val();
pass = $('#ldap_agent_password').val();
if(host && user && pass) {
param = 'action=guessPortAndTLS'+
'&ldap_serverconfig_chooser='+$('#ldap_serverconfig_chooser').val();
LdapWizard.showSpinner('#ldap_port');
LdapWizard.ajax(param,
function(result) {
LdapWizard.applyChanges(result);
LdapWizard.hideSpinner('#ldap_port');
if($('#ldap_port').val()) {
LdapWizard.checkBaseDN();
$('#ldap_port').removeClass('invisible');
LdapWizard.hideInfoBox();
}
},
function (result) {
LdapWizard.hideSpinner('#ldap_port');
$('#ldap_port').removeClass('invisible');
LdapWizard.showInfoBox('Please specify the BaseDN');
}
);
}
},
composeFilter: function(type) {
if(type == 'user') {
action = 'getUserListFilter';
} else if(type == 'login') {
action = 'getUserLoginFilter';
} else if(type == 'group') {
action = 'getGroupFilter';
}
param = 'action='+action+
'&ldap_serverconfig_chooser='+$('#ldap_serverconfig_chooser').val();
LdapWizard.ajax(param,
function(result) {
LdapWizard.applyChanges(result);
if(type == 'user') {
LdapWizard.countUsers();
} else if(type == 'group') {
LdapWizard.countGroups();
LdapWizard.detectGroupMemberAssoc();
}
},
function (result) {
// error handling
}
);
},
controlBack: function() {
curTabIndex = $('#ldapSettings').tabs('option', 'active');
if(curTabIndex == 0) {
return;
}
if(curTabIndex == 1) {
$('.ldap_action_back').addClass('invisible');
}
$('#ldapSettings').tabs('option', 'active', curTabIndex - 1);
if(curTabIndex == 3) {
$('.ldap_action_continue').removeClass('invisible');
}
},
controlContinue: function() {
curTabIndex = $('#ldapSettings').tabs('option', 'active');
if(curTabIndex == 3) {
return;
}
$('#ldapSettings').tabs('option', 'active', 1 + curTabIndex);
if(curTabIndex == 2) {
//now last tab
$('.ldap_action_continue').addClass('invisible');
}
if(curTabIndex == 0) {
$('.ldap_action_back').removeClass('invisible');
}
},
_countThings: function(method) {
param = 'action='+method+
'&ldap_serverconfig_chooser='+$('#ldap_serverconfig_chooser').val();
LdapWizard.ajax(param,
function(result) {
LdapWizard.applyChanges(result);
},
function (result) {
// error handling
}
);
},
countGroups: function() {
LdapWizard._countThings('countGroups');
},
countUsers: function() {
LdapWizard._countThings('countUsers');
},
detectGroupMemberAssoc: function() {
param = 'action=determineGroupMemberAssoc'+
'&ldap_serverconfig_chooser='+$('#ldap_serverconfig_chooser').val();
LdapWizard.ajax(param,
function(result) {
//pure background story
},
function (result) {
// error handling
}
);
},
findAttributes: function() {
param = 'action=determineAttributes'+
'&ldap_serverconfig_chooser='+$('#ldap_serverconfig_chooser').val();
LdapWizard.showSpinner('#ldap_loginfilter_attributes');
LdapWizard.ajax(param,
function(result) {
$('#ldap_loginfilter_attributes').find('option').remove();
for (i in result.options['ldap_loginfilter_attributes']) {
//FIXME: move HTML into template
attr = result.options['ldap_loginfilter_attributes'][i];
$('#ldap_loginfilter_attributes').append(
"<option value='"+attr+"'>"+attr+"</option>");
}
LdapWizard.hideSpinner('#ldap_loginfilter_attributes');
LdapWizard.applyChanges(result);
$('#ldap_loginfilter_attributes').multiselect('refresh');
$('#ldap_loginfilter_attributes').multiselect('enable');
},
function (result) {
//deactivate if no attributes found
$('#ldap_loginfilter_attributes').multiselect(
{noneSelectedText : 'No attributes found'});
$('#ldap_loginfilter_attributes').multiselect('disable');
LdapWizard.hideSpinner('#ldap_loginfilter_attributes');
}
);
},
findAvailableGroups: function(multisel, type) {
if(type != 'Users' && type != 'Groups') {
return false;
}
param = 'action=determineGroupsFor'+type+
'&ldap_serverconfig_chooser='+$('#ldap_serverconfig_chooser').val();
LdapWizard.showSpinner('#'+multisel);
LdapWizard.ajax(param,
function(result) {
$('#'+multisel).find('option').remove();
for (i in result.options[multisel]) {
//FIXME: move HTML into template
objc = result.options[multisel][i];
$('#'+multisel).append("<option value='"+objc+"'>"+objc+"</option>");
}
LdapWizard.hideSpinner('#'+multisel);
LdapWizard.applyChanges(result);
$('#'+multisel).multiselect('refresh');
$('#'+multisel).multiselect('enable');
},
function (result) {
LdapWizard.hideSpinner('#'+multisel);
$('#'+multisel).multiselect('disable');
}
);
},
findObjectClasses: function(multisel, type) {
if(type != 'User' && type != 'Group') {
return false;
}
param = 'action=determine'+type+'ObjectClasses'+
'&ldap_serverconfig_chooser='+$('#ldap_serverconfig_chooser').val();
LdapWizard.showSpinner('#'+multisel);
LdapWizard.ajax(param,
function(result) {
$('#'+multisel).find('option').remove();
for (i in result.options[multisel]) {
//FIXME: move HTML into template
objc = result.options[multisel][i];
$('#'+multisel).append("<option value='"+objc+"'>"+objc+"</option>");
}
LdapWizard.hideSpinner('#'+multisel);
LdapWizard.applyChanges(result);
$('#'+multisel).multiselect('refresh');
},
function (result) {
LdapWizard.hideSpinner('#'+multisel);
//TODO: error handling
}
);
},
functionalityCheck: function() {
//criterias to enable the connection:
// - host, port, user filter, login filter
host = $('#ldap_host').val();
port = $('#ldap_port').val();
userfilter = $('#ldap_dn').val();
loginfilter = $('#ldap_agent_password').val();
//FIXME: activates a manually deactivated configuration.
if(host && port && userfilter && loginfilter) {
if($('#ldap_configuration_active').is(':checked')) {
return;
}
$('#ldap_configuration_active').prop('checked', true);
LdapWizard.save($('#ldap_configuration_active')[0]);
} else {
if($('#ldap_configuration_active').is(':checked')) {
$('#ldap_configuration_active').prop('checked', false);
LdapWizard.save($('#ldap_configuration_active')[0]);
}
}
},
hideInfoBox: function() {
if(LdapWizard.checkInfoShown) {
$('#ldapWizard1 .ldapWizardInfo').addClass('invisible');
LdapWizard.checkInfoShown = false;
}
},
hideSpinner: function(id) {
$(id+' + .wizSpinner').remove();
$(id + " + button").css('display', 'inline');
},
init: function() {
if($('#ldap_port').val()) {
$('#ldap_port').removeClass('invisible');
}
if($('#ldap_base').val()) {
$('#ldap_base').removeClass('invisible');
}
LdapWizard.basicStatusCheck();
},
initGroupFilter: function() {
LdapWizard.findObjectClasses('ldap_groupfilter_objectclass', 'Group');
LdapWizard.findAvailableGroups('ldap_groupfilter_groups', 'Groups');
LdapWizard.composeFilter('group');
LdapWizard.countGroups();
},
initLoginFilter: function() {
LdapWizard.findAttributes();
LdapWizard.composeFilter('login');
},
initMultiSelect: function(object, id, caption) {
object.multiselect({
header: false,
selectedList: 9,
noneSelectedText: caption,
click: function(event, ui) {
LdapWizard.saveMultiSelect(id,
$('#'+id).multiselect("getChecked"));
}
});
},
initUserFilter: function() {
LdapWizard.findObjectClasses('ldap_userfilter_objectclass', 'User');
LdapWizard.findAvailableGroups('ldap_userfilter_groups', 'Users');
LdapWizard.composeFilter('user');
LdapWizard.countUsers();
},
onTabChange: function(event, ui) {
if(ui.newTab[0].id === '#ldapWizard2') {
LdapWizard.initUserFilter();
} else if(ui.newTab[0].id === '#ldapWizard3') {
LdapWizard.initLoginFilter();
} else if(ui.newTab[0].id === '#ldapWizard4') {
LdapWizard.initGroupFilter();
}
},
processChanges: function(triggerObj) {
if(triggerObj.id == 'ldap_host'
|| triggerObj.id == 'ldap_port'
|| triggerObj.id == 'ldap_dn'
|| triggerObj.id == 'ldap_agent_password') {
LdapWizard.checkPort();
if($('#ldap_port').val()) {
//if Port is already set, check BaseDN
LdapWizard.checkBaseDN();
}
}
if(triggerObj.id == 'ldap_userlist_filter') {
LdapWizard.countUsers();
} else if(triggerObj.id == 'ldap_group_filter') {
LdapWizard.countGroups();
LdapWizard.detectGroupMemberAssoc();
}
if(triggerObj.id == 'ldap_loginfilter_username'
|| triggerObj.id == 'ldap_loginfilter_email') {
LdapWizard.composeFilter('login');
}
if($('#ldapSettings').tabs('option', 'active') == 0) {
LdapWizard.basicStatusCheck();
}
},
save: function(inputObj) {
if(LdapWizard.saveBlacklist.hasOwnProperty(inputObj.id)) {
delete LdapWizard.saveBlacklist[inputObj.id];
return;
}
if($(inputObj).is('input[type=checkbox]')
&& !$(inputObj).is(':checked')) {
val = 0;
} else {
val = $(inputObj).val();
}
LdapWizard._save(inputObj, val);
},
saveMultiSelect: function(originalObj, resultObj) {
values = '';
for(i = 0; i < resultObj.length; i++) {
values = values + "\n" + resultObj[i].value;
}
LdapWizard._save($('#'+originalObj)[0], $.trim(values));
if(originalObj == 'ldap_userfilter_objectclass'
|| originalObj == 'ldap_userfilter_groups') {
LdapWizard.composeFilter('user');
//when user filter is changed afterwards, login filter needs to
//be adjusted, too
LdapWizard.composeFilter('login');
} else if(originalObj == 'ldap_loginfilter_attributes') {
LdapWizard.composeFilter('login');
} else if(originalObj == 'ldap_groupfilter_objectclass'
|| originalObj == 'ldap_groupfilter_groups') {
LdapWizard.composeFilter('group');
}
},
_save: function(object, value) {
param = 'cfgkey='+object.id+
'&cfgval='+value+
'&action=save'+
'&ldap_serverconfig_chooser='+$('#ldap_serverconfig_chooser').val();
$.post(
OC.filePath('user_ldap','ajax','wizard.php'),
param,
function(result) {
if(result.status == 'success') {
LdapWizard.processChanges(object);
} else {
// alert('Oooooooooooh :(');
}
}
);
},
showInfoBox: function(text) {
$('#ldapWizard1 .ldapWizardInfo').text(t('user_ldap', text));
$('#ldapWizard1 .ldapWizardInfo').removeClass('invisible');
LdapWizard.checkInfoShown = true;
},
showSpinner: function(id) {
if($(id + ' + .wizSpinner').length == 0) {
$(LdapWizard.spinner).insertAfter($(id));
$(id + " + img + button").css('display', 'none');
}
},
toggleRawFilter: function(container, moc, mg, stateVar) {
if($(container).hasClass('invisible')) {
$(container).removeClass('invisible');
$(moc).multiselect('disable');
if($(mg).multiselect().attr('disabled') == 'disabled') {
LdapWizard[stateVar] = 'disable';
} else {
LdapWizard[stateVar] = 'enable';
}
$(mg).multiselect('disable');
} else {
$(container).addClass('invisible');
$(mg).multiselect(LdapWizard[stateVar]);
$(moc).multiselect('enable');
}
},
toggleRawGroupFilter: function() {
LdapWizard.toggleRawFilter('#rawGroupFilterContainer',
'#ldap_groupfilter_objectclass',
'#ldap_groupfilter_groups',
'groupFilterGroupSelectState'
);
},
toggleRawUserFilter: function() {
LdapWizard.toggleRawFilter('#rawUserFilterContainer',
'#ldap_userfilter_objectclass',
'#ldap_userfilter_groups',
'userFilterGroupSelectState'
);
}
};
$(document).ready(function() {
$('#ldapAdvancedAccordion').accordion({ heightStyle: 'content', animate: 'easeInOutCirc'});
$('#ldapSettings').tabs();
$('#ldapSettings').tabs({ beforeActivate: LdapWizard.onTabChange });
$('#ldap_submit').button();
$('#ldap_action_test_connection').button();
$('#ldap_action_delete_configuration').button();
LdapWizard.initMultiSelect($('#ldap_userfilter_groups'),
'ldap_userfilter_groups',
t('user_ldap', 'Select groups'));
LdapWizard.initMultiSelect($('#ldap_userfilter_objectclass'),
'ldap_userfilter_objectclass',
t('user_ldap', 'Select object classes'));
LdapWizard.initMultiSelect($('#ldap_loginfilter_attributes'),
'ldap_loginfilter_attributes',
t('user_ldap', 'Select attributes'));
LdapWizard.initMultiSelect($('#ldap_groupfilter_groups'),
'ldap_groupfilter_groups',
t('user_ldap', 'Select groups'));
LdapWizard.initMultiSelect($('#ldap_groupfilter_objectclass'),
'ldap_groupfilter_objectclass',
t('user_ldap', 'Select object classes'));
$('.lwautosave').change(function() { LdapWizard.save(this); });
$('#toggleRawUserFilter').click(LdapWizard.toggleRawUserFilter);
$('#toggleRawGroupFilter').click(LdapWizard.toggleRawGroupFilter);
LdapConfiguration.refreshConfig();
$('.ldap_action_continue').click(function(event) {
event.preventDefault();
LdapWizard.controlContinue();
});
$('.ldap_action_back').click(function(event) {
event.preventDefault();
LdapWizard.controlBack();
});
$('#ldap_action_test_connection').click(function(event){
event.preventDefault();
$.post(

View File

@ -831,7 +831,7 @@ class Access extends LDAPUtility {
private function combineFilter($filters, $operator) {
$combinedFilter = '('.$operator;
foreach($filters as $filter) {
if($filter[0] !== '(') {
if(!empty($filter) && $filter[0] !== '(') {
$filter = '('.$filter.')';
}
$combinedFilter.=$filter;

View File

@ -0,0 +1,384 @@
<?php
/**
* ownCloud LDAP Connection
*
* @author Arthur Schiwon
* @copyright 2012, 2013 Arthur Schiwon blizzz@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/>.
*
*/
namespace OCA\user_ldap\lib;
class Configuration {
protected $configPrefix = null;
protected $configRead = false;
//settings
protected $config = array(
'ldapHost' => null,
'ldapPort' => null,
'ldapBackupHost' => null,
'ldapBackupPort' => null,
'ldapBase' => null,
'ldapBaseUsers' => null,
'ldapBaseGroups' => null,
'ldapAgentName' => null,
'ldapAgentPassword' => null,
'ldapTLS' => null,
'ldapNoCase' => null,
'turnOffCertCheck' => null,
'ldapIgnoreNamingRules' => null,
'ldapUserDisplayName' => null,
'ldapUserFilterObjectclass' => null,
'ldapUserFilterGroups' => null,
'ldapUserFilter' => null,
'ldapGroupFilter' => null,
'ldapGroupFilterObjectclass' => null,
'ldapGroupFilterGroups' => null,
'ldapGroupDisplayName' => null,
'ldapGroupMemberAssocAttr' => null,
'ldapLoginFilter' => null,
'ldapLoginFilterEmail' => null,
'ldapLoginFilterUsername' => null,
'ldapLoginFilterAttributes' => null,
'ldapQuotaAttribute' => null,
'ldapQuotaDefault' => null,
'ldapEmailAttribute' => null,
'ldapCacheTTL' => null,
'ldapUuidUserAttribute' => 'auto',
'ldapUuidGroupAttribute' => 'auto',
'ldapOverrideMainServer' => false,
'ldapConfigurationActive' => false,
'ldapAttributesForUserSearch' => null,
'ldapAttributesForGroupSearch' => null,
'homeFolderNamingRule' => null,
'hasPagedResultSupport' => false,
'hasMemberOfFilterSupport' => false,
'ldapExpertUsernameAttr' => null,
'ldapExpertUUIDUserAttr' => null,
'ldapExpertUUIDGroupAttr' => null,
);
public function __construct($configPrefix, $autoread = true) {
$this->configPrefix = $configPrefix;
if($autoread) {
$this->readConfiguration();
}
}
public function __get($name) {
if(isset($this->config[$name])) {
return $this->config[$name];
}
}
public function __set($name, $value) {
$this->setConfiguration(array($name => $value));
}
public function getConfiguration() {
return $this->config;
}
/**
* @brief set LDAP configuration with values delivered by an array, not read
* from configuration. It does not save the configuration! To do so, you
* must call saveConfiguration afterwards.
* @param $config array that holds the config parameters in an associated
* array
* @param &$applied optional; array where the set fields will be given to
* @return null
*/
public function setConfiguration($config, &$applied = null) {
if(!is_array($config)) {
return false;
}
$cta = $this->getConfigTranslationArray();
foreach($config as $inputkey => $val) {
if(strpos($inputkey, '_') !== false && isset($cta[$inputkey])) {
$key = $cta[$inputkey];
} elseif(isset($this->config[$inputkey])) {
$key = $inputkey;
} else {
continue;
}
$setMethod = 'setValue';
switch($key) {
case 'homeFolderNamingRule':
if(!empty($val) && strpos($val, 'attr:') === false) {
$val = 'attr:'.$val;
}
case 'ldapBase':
case 'ldapBaseUsers':
case 'ldapBaseGroups':
case 'ldapAttributesForUserSearch':
case 'ldapAttributesForGroupSearch':
case 'ldapUserFilterObjectclass':
case 'ldapUserFilterGroups':
case 'ldapGroupFilterObjectclass':
case 'ldapGroupFilterGroups':
case 'ldapLoginFilterAttributes':
$setMethod = 'setMultiLine';
default:
$this->$setMethod($key, $val);
if(is_array($applied)) {
$applied[] = $inputkey;
}
}
}
}
public function readConfiguration() {
if(!$this->configRead && !is_null($this->configPrefix)) {
$cta = array_flip($this->getConfigTranslationArray());
foreach($this->config as $key => $val) {
if(!isset($cta[$key])) {
//some are determined
continue;
}
$dbkey = $cta[$key];
switch($key) {
case 'ldapBase':
case 'ldapBaseUsers':
case 'ldapBaseGroups':
case 'ldapAttributesForUserSearch':
case 'ldapAttributesForGroupSearch':
case 'ldapUserFilterObjectclass':
case 'ldapUserFilterGroups':
case 'ldapGroupFilterObjectclass':
case 'ldapGroupFilterGroups':
case 'ldapLoginFilterAttributes':
$readMethod = 'getMultiLine';
break;
case 'ldapIgnoreNamingRules':
$readMethod = 'getSystemValue';
$dbkey = $key;
break;
case 'ldapAgentPassword':
$readMethod = 'getPwd';
break;
case 'ldapUserDisplayName':
case 'ldapGroupDisplayName':
$readMethod = 'getLcValue';
break;
default:
$readMethod = 'getValue';
break;
}
$this->config[$key] = $this->$readMethod($dbkey);
}
$this->configRead = true;
}
}
/**
* @brief saves the current Configuration in the database
*/
public function saveConfiguration() {
$cta = array_flip($this->getConfigTranslationArray());
foreach($this->config as $key => $value) {
switch ($key) {
case 'ldapAgentPassword':
$value = base64_encode($value);
break;
case 'ldapBase':
case 'ldapBaseUsers':
case 'ldapBaseGroups':
case 'ldapAttributesForUserSearch':
case 'ldapAttributesForGroupSearch':
case 'ldapUserFilterObjectclass':
case 'ldapUserFilterGroups':
case 'ldapGroupFilterObjectclass':
case 'ldapGroupFilterGroups':
case 'ldapLoginFilterAttributes':
if(is_array($value)) {
$value = implode("\n", $value);
}
break;
//following options are not stored but detected, skip them
case 'ldapIgnoreNamingRules':
case 'hasPagedResultSupport':
case 'ldapUuidUserAttribute':
case 'ldapUuidGroupAttribute':
continue 2;
}
if(is_null($value)) {
$value = '';
}
$this->saveValue($cta[$key], $value);
}
}
protected function getMultiLine($varname) {
$value = $this->getValue($varname);
if(empty($value)) {
$value = '';
} else {
$value = preg_split('/\r\n|\r|\n/', $value);
}
return $value;
}
protected function setMultiLine($varname, $value) {
if(empty($value)) {
$value = '';
} else {
$value = preg_split('/\r\n|\r|\n/', $value);
if($value === false) {
$value = '';
}
}
$this->setValue($varname, $value);
}
protected function getPwd($varname) {
return base64_decode($this->getValue($varname));
}
protected function getLcValue($varname) {
return mb_strtolower($this->getValue($varname), 'UTF-8');
}
protected function getSystemValue($varname) {
//FIXME: if another system value is added, softcode the default value
return \OCP\Config::getSystemValue($varname, false);
}
protected function getValue($varname) {
static $defaults;
if(is_null($defaults)) {
$defaults = $this->getDefaults();
}
return \OCP\Config::getAppValue('user_ldap',
$this->configPrefix.$varname,
$defaults[$varname]);
}
protected function setValue($varname, $value) {
$this->config[$varname] = $value;
}
protected function saveValue($varname, $value) {
return \OCP\Config::setAppValue('user_ldap',
$this->configPrefix.$varname,
$value);
}
/**
* @returns an associative array with the default values. Keys are correspond
* to config-value entries in the database table
*/
public function getDefaults() {
return array(
'ldap_host' => '',
'ldap_port' => '',
'ldap_backup_host' => '',
'ldap_backup_port' => '',
'ldap_override_main_server' => '',
'ldap_dn' => '',
'ldap_agent_password' => '',
'ldap_base' => '',
'ldap_base_users' => '',
'ldap_base_groups' => '',
'ldap_userlist_filter' => '',
'ldap_userfilter_objectclass' => '',
'ldap_userfilter_groups' => '',
'ldap_login_filter' => 'uid=%uid',
'ldap_loginfilter_email' => 0,
'ldap_loginfilter_username' => 1,
'ldap_loginfilter_attributes' => '',
'ldap_group_filter' => '',
'ldap_groupfilter_objectclass' => '',
'ldap_groupfilter_groups' => '',
'ldap_display_name' => 'displayName',
'ldap_group_display_name' => 'cn',
'ldap_tls' => 1,
'ldap_nocase' => 0,
'ldap_quota_def' => '',
'ldap_quota_attr' => '',
'ldap_email_attr' => '',
'ldap_group_member_assoc_attribute' => 'uniqueMember',
'ldap_cache_ttl' => 600,
'ldap_uuid_user_attribute' => 'auto',
'ldap_uuid_group_attribute' => 'auto',
'home_folder_naming_rule' => '',
'ldap_turn_off_cert_check' => 0,
'ldap_configuration_active' => 0,
'ldap_attributes_for_user_search' => '',
'ldap_attributes_for_group_search' => '',
'ldap_expert_username_attr' => '',
'ldap_expert_uuid_user_attr' => '',
'ldap_expert_uuid_group_attr' => '',
'has_memberof_filter_support' => 0,
);
}
/**
* @return returns an array that maps internal variable names to database fields
*/
public function getConfigTranslationArray() {
//TODO: merge them into one representation
static $array = array(
'ldap_host' => 'ldapHost',
'ldap_port' => 'ldapPort',
'ldap_backup_host' => 'ldapBackupHost',
'ldap_backup_port' => 'ldapBackupPort',
'ldap_override_main_server' => 'ldapOverrideMainServer',
'ldap_dn' => 'ldapAgentName',
'ldap_agent_password' => 'ldapAgentPassword',
'ldap_base' => 'ldapBase',
'ldap_base_users' => 'ldapBaseUsers',
'ldap_base_groups' => 'ldapBaseGroups',
'ldap_userfilter_objectclass' => 'ldapUserFilterObjectclass',
'ldap_userfilter_groups' => 'ldapUserFilterGroups',
'ldap_userlist_filter' => 'ldapUserFilter',
'ldap_login_filter' => 'ldapLoginFilter',
'ldap_loginfilter_email' => 'ldapLoginFilterEmail',
'ldap_loginfilter_username' => 'ldapLoginFilterUsername',
'ldap_loginfilter_attributes' => 'ldapLoginFilterAttributes',
'ldap_group_filter' => 'ldapGroupFilter',
'ldap_groupfilter_objectclass' => 'ldapGroupFilterObjectclass',
'ldap_groupfilter_groups' => 'ldapGroupFilterGroups',
'ldap_display_name' => 'ldapUserDisplayName',
'ldap_group_display_name' => 'ldapGroupDisplayName',
'ldap_tls' => 'ldapTLS',
'ldap_nocase' => 'ldapNoCase',
'ldap_quota_def' => 'ldapQuotaDefault',
'ldap_quota_attr' => 'ldapQuotaAttribute',
'ldap_email_attr' => 'ldapEmailAttribute',
'ldap_group_member_assoc_attribute' => 'ldapGroupMemberAssocAttr',
'ldap_cache_ttl' => 'ldapCacheTTL',
'home_folder_naming_rule' => 'homeFolderNamingRule',
'ldap_turn_off_cert_check' => 'turnOffCertCheck',
'ldap_configuration_active' => 'ldapConfigurationActive',
'ldap_attributes_for_user_search' => 'ldapAttributesForUserSearch',
'ldap_attributes_for_group_search' => 'ldapAttributesForGroupSearch',
'ldap_expert_username_attr' => 'ldapExpertUsernameAttr',
'ldap_expert_uuid_user_attr' => 'ldapExpertUUIUserDAttr',
'ldap_expert_uuid_group_attr' => 'ldapExpertUUIDGroupAttr',
'has_memberof_filter_support' => 'hasMemberOfFilterSupport',
);
return $array;
}
}

View File

@ -1,7 +1,7 @@
<?php
/**
* ownCloud LDAP Access
* ownCloud LDAP Connection
*
* @author Arthur Schiwon
* @copyright 2012, 2013 Arthur Schiwon blizzz@owncloud.com
@ -31,48 +31,13 @@ class Connection extends LDAPUtility {
//whether connection should be kept on __destruct
private $dontDestruct = false;
private $hasPagedResultSupport = true;
//cache handler
protected $cache;
//settings
protected $config = array(
'ldapHost' => null,
'ldapPort' => null,
'ldapBackupHost' => null,
'ldapBackupPort' => null,
'ldapBase' => null,
'ldapBaseUsers' => null,
'ldapBaseGroups' => null,
'ldapAgentName' => null,
'ldapAgentPassword' => null,
'ldapTLS' => null,
'ldapNoCase' => null,
'turnOffCertCheck' => null,
'ldapIgnoreNamingRules' => null,
'ldapUserDisplayName' => null,
'ldapUserFilter' => null,
'ldapGroupFilter' => null,
'ldapGroupDisplayName' => null,
'ldapGroupMemberAssocAttr' => null,
'ldapLoginFilter' => null,
'ldapQuotaAttribute' => null,
'ldapQuotaDefault' => null,
'ldapEmailAttribute' => null,
'ldapCacheTTL' => null,
'ldapUuidUserAttribute' => 'auto',
'ldapUuidGroupAttribute' => 'auto',
'ldapOverrideUuidAttribute' => null,
'ldapOverrideMainServer' => false,
'ldapConfigurationActive' => false,
'ldapAttributesForUserSearch' => null,
'ldapAttributesForGroupSearch' => null,
'homeFolderNamingRule' => null,
'hasPagedResultSupport' => false,
'ldapExpertUsernameAttr' => null,
'ldapExpertUUIDUserAttr' => null,
'ldapExpertUUIDGroupAttr' => null,
);
//settings handler
protected $configuration;
/**
* @brief Constructor
@ -83,13 +48,14 @@ class Connection extends LDAPUtility {
parent::__construct($ldap);
$this->configPrefix = $configPrefix;
$this->configID = $configID;
$this->configuration = new Configuration($configPrefix);
$memcache = new \OC\Memcache\Factory();
if($memcache->isAvailable()) {
$this->cache = $memcache->create();
} else {
$this->cache = \OC_Cache::getGlobalCache();
}
$this->config['hasPagedResultSupport'] =
$this->hasPagedResultSupport =
$this->ldap->hasPagedResultSupport();
}
@ -114,23 +80,21 @@ class Connection extends LDAPUtility {
$this->readConfiguration();
}
if(isset($this->config[$name])) {
return $this->config[$name];
if($name === 'hasPagedResultSupport') {
return $this->hasPagedResultSupport;
}
return $this->configuration->$name;
}
public function __set($name, $value) {
$changed = false;
//only few options are writable
if($name === 'ldapUuidUserAttribute' || $name === 'ldapUuidGroupAttribute') {
\OCP\Util::writeLog('user_ldap', 'Set config '.$name.' to '.$value, \OCP\Util::DEBUG);
$this->config[$name] = $value;
$before = $this->configuration->$name;
$this->configuration->$name = $value;
$after = $this->configuration->$name;
if($before !== $after) {
if(!empty($this->configID)) {
\OCP\Config::setAppValue($this->configID, $this->configPrefix.$name, $value);
$this->configuration->saveConfiguration();
}
$changed = true;
}
if($changed) {
$this->validateConfiguration();
}
}
@ -174,7 +138,7 @@ class Connection extends LDAPUtility {
if(!$this->configured) {
$this->readConfiguration();
}
if(!$this->config['ldapCacheTTL']) {
if(!$this->configuration->ldapCacheTTL) {
return null;
}
if(!$this->isCached($key)) {
@ -190,7 +154,7 @@ class Connection extends LDAPUtility {
if(!$this->configured) {
$this->readConfiguration();
}
if(!$this->config['ldapCacheTTL']) {
if(!$this->configuration->ldapCacheTTL) {
return false;
}
$key = $this->getCacheKey($key);
@ -201,156 +165,32 @@ class Connection extends LDAPUtility {
if(!$this->configured) {
$this->readConfiguration();
}
if(!$this->config['ldapCacheTTL']
|| !$this->config['ldapConfigurationActive']) {
if(!$this->configuration->ldapCacheTTL
|| !$this->configuration->ldapConfigurationActive) {
return null;
}
$key = $this->getCacheKey($key);
$value = base64_encode(serialize($value));
$this->cache->set($key, $value, $this->config['ldapCacheTTL']);
$this->cache->set($key, $value, $this->configuration->ldapCacheTTL);
}
public function clearCache() {
$this->cache->clear($this->getCacheKey(null));
}
private function getValue($varname) {
static $defaults;
if(is_null($defaults)) {
$defaults = $this->getDefaults();
}
return \OCP\Config::getAppValue($this->configID,
$this->configPrefix.$varname,
$defaults[$varname]);
}
private function setValue($varname, $value) {
\OCP\Config::setAppValue($this->configID,
$this->configPrefix.$varname,
$value);
}
/**
* Special handling for reading Base Configuration
*
* @param $base the internal name of the config key
* @param $value the value stored for the base
*/
private function readBase($base, $value) {
if(empty($value)) {
$value = '';
} else {
$value = preg_split('/\r\n|\r|\n/', $value);
}
$this->config[$base] = $value;
}
/**
* Caches the general LDAP configuration.
* @brief Caches the general LDAP configuration.
* @param $force optional. true, if the re-read should be forced. defaults
* to false.
* @return null
*/
private function readConfiguration($force = false) {
if((!$this->configured || $force) && !is_null($this->configID)) {
$v = 'getValue';
$this->config['ldapHost'] = $this->$v('ldap_host');
$this->config['ldapBackupHost'] = $this->$v('ldap_backup_host');
$this->config['ldapPort'] = $this->$v('ldap_port');
$this->config['ldapBackupPort'] = $this->$v('ldap_backup_port');
$this->config['ldapOverrideMainServer']
= $this->$v('ldap_override_main_server');
$this->config['ldapAgentName'] = $this->$v('ldap_dn');
$this->config['ldapAgentPassword']
= base64_decode($this->$v('ldap_agent_password'));
$this->readBase('ldapBase', $this->$v('ldap_base'));
$this->readBase('ldapBaseUsers', $this->$v('ldap_base_users'));
$this->readBase('ldapBaseGroups', $this->$v('ldap_base_groups'));
$this->config['ldapTLS'] = $this->$v('ldap_tls');
$this->config['ldapNoCase'] = $this->$v('ldap_nocase');
$this->config['turnOffCertCheck']
= $this->$v('ldap_turn_off_cert_check');
$this->config['ldapUserDisplayName']
= mb_strtolower($this->$v('ldap_display_name'), 'UTF-8');
$this->config['ldapUserFilter']
= $this->$v('ldap_userlist_filter');
$this->config['ldapGroupFilter'] = $this->$v('ldap_group_filter');
$this->config['ldapLoginFilter'] = $this->$v('ldap_login_filter');
$this->config['ldapGroupDisplayName']
= mb_strtolower($this->$v('ldap_group_display_name'), 'UTF-8');
$this->config['ldapQuotaAttribute']
= $this->$v('ldap_quota_attr');
$this->config['ldapQuotaDefault']
= $this->$v('ldap_quota_def');
$this->config['ldapEmailAttribute']
= $this->$v('ldap_email_attr');
$this->config['ldapGroupMemberAssocAttr']
= $this->$v('ldap_group_member_assoc_attribute');
$this->config['ldapIgnoreNamingRules']
= \OCP\Config::getSystemValue('ldapIgnoreNamingRules', false);
$this->config['ldapCacheTTL'] = $this->$v('ldap_cache_ttl');
$this->config['ldapUuidUserAttribute']
= $this->$v('ldap_uuid_user_attribute');
$this->config['ldapUuidGroupAttribute']
= $this->$v('ldap_uuid_group_attribute');
$this->config['ldapOverrideUuidAttribute']
= $this->$v('ldap_override_uuid_attribute');
$this->config['homeFolderNamingRule']
= $this->$v('home_folder_naming_rule');
$this->config['ldapConfigurationActive']
= $this->$v('ldap_configuration_active');
$this->config['ldapAttributesForUserSearch']
= preg_split('/\r\n|\r|\n/', $this->$v('ldap_attributes_for_user_search'));
$this->config['ldapAttributesForGroupSearch']
= preg_split('/\r\n|\r|\n/', $this->$v('ldap_attributes_for_group_search'));
$this->config['ldapExpertUsernameAttr']
= $this->$v('ldap_expert_username_attr');
$this->config['ldapExpertUUIDUserAttr']
= $this->$v('ldap_expert_uuid_user_attr');
$this->config['ldapExpertUUIDGroupAttr']
= $this->$v('ldap_expert_uuid_group_attr');
$this->configuration->readConfiguration();
$this->configured = $this->validateConfiguration();
}
}
/**
* @return returns an array that maps internal variable names to database fields
*/
private function getConfigTranslationArray() {
static $array = array(
'ldap_host'=>'ldapHost',
'ldap_port'=>'ldapPort',
'ldap_backup_host'=>'ldapBackupHost',
'ldap_backup_port'=>'ldapBackupPort',
'ldap_override_main_server' => 'ldapOverrideMainServer',
'ldap_dn'=>'ldapAgentName',
'ldap_agent_password'=>'ldapAgentPassword',
'ldap_base'=>'ldapBase',
'ldap_base_users'=>'ldapBaseUsers',
'ldap_base_groups'=>'ldapBaseGroups',
'ldap_userlist_filter'=>'ldapUserFilter',
'ldap_login_filter'=>'ldapLoginFilter',
'ldap_group_filter'=>'ldapGroupFilter',
'ldap_display_name'=>'ldapUserDisplayName',
'ldap_group_display_name'=>'ldapGroupDisplayName',
'ldap_tls'=>'ldapTLS',
'ldap_nocase'=>'ldapNoCase',
'ldap_quota_def'=>'ldapQuotaDefault',
'ldap_quota_attr'=>'ldapQuotaAttribute',
'ldap_email_attr'=>'ldapEmailAttribute',
'ldap_group_member_assoc_attribute'=>'ldapGroupMemberAssocAttr',
'ldap_cache_ttl'=>'ldapCacheTTL',
'home_folder_naming_rule' => 'homeFolderNamingRule',
'ldap_turn_off_cert_check' => 'turnOffCertCheck',
'ldap_configuration_active' => 'ldapConfigurationActive',
'ldap_attributes_for_user_search' => 'ldapAttributesForUserSearch',
'ldap_attributes_for_group_search' => 'ldapAttributesForGroupSearch',
'ldap_expert_username_attr' => 'ldapExpertUsernameAttr',
'ldap_expert_uuid_user_attr' => 'ldapExpertUUIDUserAttr',
'ldap_expert_uuid_group_attr' => 'ldapExpertUUIDGroupAttr',
);
return $array;
}
/**
* @brief set LDAP configuration with values delivered by an array, not read from configuration
* @param $config array that holds the config parameters in an associated array
@ -358,79 +198,24 @@ class Connection extends LDAPUtility {
* @return true if config validates, false otherwise. Check with $setParameters for detailed success on single parameters
*/
public function setConfiguration($config, &$setParameters = null) {
if(!is_array($config)) {
return false;
if(is_null($setParameters)) {
$setParameters = array();
}
$params = $this->getConfigTranslationArray();
foreach($config as $parameter => $value) {
if(($parameter === 'homeFolderNamingRule'
|| (isset($params[$parameter])
&& $params[$parameter] === 'homeFolderNamingRule'))
&& !empty($value)) {
$value = 'attr:'.$value;
} else if (strpos($parameter, 'ldapBase') !== false
|| (isset($params[$parameter])
&& strpos($params[$parameter], 'ldapBase') !== false)) {
$this->readBase($params[$parameter], $value);
if(is_array($setParameters)) {
$setParameters[] = $parameter;
}
continue;
}
if(isset($this->config[$parameter])) {
$this->config[$parameter] = $value;
if(is_array($setParameters)) {
$setParameters[] = $parameter;
}
} else if(isset($params[$parameter])) {
$this->config[$params[$parameter]] = $value;
if(is_array($setParameters)) {
$setParameters[] = $params[$parameter];
}
}
$this->configuration->setConfiguration($config, $setParameters);
if(count($setParameters) > 0) {
$this->configured = $this->validateConfiguration();
}
$this->configured = $this->validateConfiguration();
return $this->configured;
}
/**
* @brief saves the current Configuration in the database
* @brief saves the current Configuration in the database and empties the
* cache
* @return null
*/
public function saveConfiguration() {
$trans = array_flip($this->getConfigTranslationArray());
foreach($this->config as $key => $value) {
\OCP\Util::writeLog('user_ldap', 'LDAP: storing key '.$key.
' value '.print_r($value, true), \OCP\Util::DEBUG);
switch ($key) {
case 'ldapAgentPassword':
$value = base64_encode($value);
break;
case 'ldapBase':
case 'ldapBaseUsers':
case 'ldapBaseGroups':
case 'ldapAttributesForUserSearch':
case 'ldapAttributesForGroupSearch':
if(is_array($value)) {
$value = implode("\n", $value);
}
break;
case 'ldapIgnoreNamingRules':
case 'ldapOverrideUuidAttribute':
case 'ldapUuidUserAttribute':
case 'ldapUuidGroupAttribute':
case 'hasPagedResultSupport':
continue 2;
}
if(is_null($value)) {
$value = '';
}
$this->setValue($trans[$key], $value);
}
$this->configuration->saveConfiguration();
$this->clearCache();
}
@ -440,26 +225,175 @@ class Connection extends LDAPUtility {
*/
public function getConfiguration() {
$this->readConfiguration();
$trans = $this->getConfigTranslationArray();
$config = array();
foreach($trans as $dbKey => $classKey) {
if($classKey === 'homeFolderNamingRule') {
if(strpos($this->config[$classKey], 'attr:') === 0) {
$config[$dbKey] = substr($this->config[$classKey], 5);
} else {
$config[$dbKey] = '';
}
continue;
} else if((strpos($classKey, 'ldapBase') !== false
|| strpos($classKey, 'ldapAttributes') !== false)
&& is_array($this->config[$classKey])) {
$config[$dbKey] = implode("\n", $this->config[$classKey]);
continue;
$config = $this->configuration->getConfiguration();
$cta = $this->configuration->getConfigTranslationArray();
$result = array();
foreach($cta as $dbkey => $configkey) {
switch($configkey) {
case 'homeFolderNamingRule':
if(strpos($config[$configkey], 'attr:') === 0) {
$result[$dbkey] = substr($config[$configkey], 5);
} else {
$result[$dbkey] = '';
}
break;
case 'ldapBase':
case 'ldapBaseUsers':
case 'ldapBaseGroups':
case 'ldapAttributesForUserSearch':
case 'ldapAttributesForGroupSearch':
if(is_array($config[$configkey])) {
$result[$dbkey] = implode("\n", $config[$configkey]);
break;
} //else follows default
default:
$result[$dbkey] = $config[$configkey];
}
}
return $result;
}
private function doSoftValidation() {
//if User or Group Base are not set, take over Base DN setting
foreach(array('ldapBaseUsers', 'ldapBaseGroups') as $keyBase) {
$val = $this->configuration->$keyBase;
if(empty($val)) {
$obj = strpos('Users', $keyBase) !== false ? 'Users' : 'Groups';
\OCP\Util::writeLog('user_ldap',
'Base tree for '.$obj.
' is empty, using Base DN',
\OCP\Util::INFO);
$this->configuration->$keyBase = $this->configuration->ldapBase;
}
$config[$dbKey] = $this->config[$classKey];
}
return $config;
$groupFilter = $this->configuration->ldapGroupFilter;
if(empty($groupFilter)) {
\OCP\Util::writeLog('user_ldap',
'No group filter is specified, LDAP group '.
'feature will not be used.',
\OCP\Util::INFO);
}
foreach(array('ldapExpertUUIDUserAttr' => 'ldapUuidUserAttribute',
'ldapExpertUUIDGroupAttr' => 'ldapUuidGroupAttribute')
as $expertSetting => $effectiveSetting) {
$uuidOverride = $this->configuration->$expertSetting;
if(!empty($uuidOverride)) {
$this->configuration->$effectiveSetting = $uuidOverride;
} else {
$uuidAttributes = array('auto', 'entryuuid', 'nsuniqueid',
'objectguid', 'guid');
if(!in_array($this->configuration->$effectiveSetting,
$uuidAttributes)
&& (!is_null($this->configID))) {
$this->configuration->$effectiveSetting = 'auto';
$this->configuration->saveConfiguration();
\OCP\Util::writeLog('user_ldap',
'Illegal value for the '.
$effectiveSetting.', '.'reset to '.
'autodetect.', \OCP\Util::INFO);
}
}
}
$backupPort = $this->configuration->ldapBackupPort;
if(empty($backupPort)) {
$this->configuration->backupPort = $this->configuration->ldapPort;
}
//make sure empty search attributes are saved as simple, empty array
$sakeys = array('ldapAttributesForUserSearch',
'ldapAttributesForGroupSearch');
foreach($sakeys as $key) {
$val = $this->configuration->$key;
if(is_array($val) && count($val) === 1 && empty($val[0])) {
$this->configuration->$key = array();
}
}
if((stripos($this->configuration->ldapHost, 'ldaps://') === 0)
&& $this->configuration->ldapTLS) {
$this->configuration->ldapTLS = false;
\OCP\Util::writeLog('user_ldap',
'LDAPS (already using secure connection) and '.
'TLS do not work together. Switched off TLS.',
\OCP\Util::INFO);
}
}
private function doCriticalValidation() {
$configurationOK = true;
$errorStr = 'Configuration Error (prefix '.
strval($this->configPrefix).'): ';
//options that shall not be empty
$options = array('ldapHost', 'ldapPort', 'ldapUserDisplayName',
'ldapGroupDisplayName', 'ldapLoginFilter');
foreach($options as $key) {
$val = $this->configuration->$key;
if(empty($val)) {
switch($key) {
case 'ldapHost':
$subj = 'LDAP Host';
break;
case 'ldapPort':
$subj = 'LDAP Port';
break;
case 'ldapUserDisplayName':
$subj = 'LDAP User Display Name';
break;
case 'ldapGroupDisplayName':
$subj = 'LDAP Group Display Name';
break;
case 'ldapLoginFilter':
$subj = 'LDAP Login Filter';
break;
default:
$subj = $key;
break;
}
$configurationOK = false;
\OCP\Util::writeLog('user_ldap',
$errorStr.'No '.$subj.' given!',
\OCP\Util::WARN);
}
}
//combinations
$agent = $this->configuration->ldapAgentName;
$pwd = $this->configuration->ldapAgentPassword;
if((empty($agent) && !empty($pwd)) || (!empty($agent) && empty($pwd))) {
\OCP\Util::writeLog('user_ldap',
$errorStr.'either no password is given for the'.
'user agent or a password is given, but not an'.
'LDAP agent.',
\OCP\Util::WARN);
$configurationOK = false;
}
$base = $this->configuration->ldapBase;
$baseUsers = $this->configuration->ldapBaseUsers;
$baseGroups = $this->configuration->ldapBaseGroups;
if(empty($base) && empty($baseUsers) && empty($baseGroups)) {
\OCP\Util::writeLog('user_ldap',
$errorStr.'Not a single Base DN given.',
\OCP\Util::WARN);
$configurationOK = false;
}
if(mb_strpos($this->configuration->ldapLoginFilter, '%uid', 0, 'UTF-8')
=== false) {
\OCP\Util::writeLog('user_ldap',
$errorStr.'login filter does not contain %uid '.
'place holder.',
\OCP\Util::WARN);
$configurationOK = false;
}
return $configurationOK;
}
/**
@ -469,162 +403,19 @@ class Connection extends LDAPUtility {
private function validateConfiguration() {
// first step: "soft" checks: settings that are not really
// necessary, but advisable. If left empty, give an info message
if(empty($this->config['ldapBaseUsers'])) {
\OCP\Util::writeLog('user_ldap', 'Base tree for Users is empty, using Base DN', \OCP\Util::INFO);
$this->config['ldapBaseUsers'] = $this->config['ldapBase'];
}
if(empty($this->config['ldapBaseGroups'])) {
\OCP\Util::writeLog('user_ldap', 'Base tree for Groups is empty, using Base DN', \OCP\Util::INFO);
$this->config['ldapBaseGroups'] = $this->config['ldapBase'];
}
if(empty($this->config['ldapGroupFilter']) && empty($this->config['ldapGroupMemberAssocAttr'])) {
\OCP\Util::writeLog('user_ldap',
'No group filter is specified, LDAP group feature will not be used.',
\OCP\Util::INFO);
}
$uuidAttributes = array(
'auto', 'entryuuid', 'nsuniqueid', 'objectguid', 'guid');
$uuidSettings = array(
'ldapUuidUserAttribute' => 'ldapExpertUUIDUserAttr',
'ldapUuidGroupAttribute' => 'ldapExpertUUIDGroupAttr');
$cta = array_flip($this->getConfigTranslationArray());
foreach($uuidSettings as $defaultKey => $overrideKey) {
if( !in_array($this->config[$defaultKey], $uuidAttributes)
&& is_null($this->config[$overrideKey])
&& !is_null($this->configID)) {
\OCP\Config::setAppValue($this->configID,
$this->configPrefix.$cta[$defaultKey],
'auto');
\OCP\Util::writeLog('user_ldap',
'Illegal value for'.$defaultKey.', reset to autodetect.',
\OCP\Util::DEBUG);
}
}
$this->doSoftValidation();
if(empty($this->config['ldapBackupPort'])) {
//force default
$this->config['ldapBackupPort'] = $this->config['ldapPort'];
}
foreach(array('ldapAttributesForUserSearch', 'ldapAttributesForGroupSearch') as $key) {
if(is_array($this->config[$key])
&& count($this->config[$key]) === 1
&& empty($this->config[$key][0])) {
$this->config[$key] = array();
}
}
if((strpos($this->config['ldapHost'], 'ldaps') === 0)
&& $this->config['ldapTLS']) {
$this->config['ldapTLS'] = false;
\OCP\Util::writeLog('user_ldap',
'LDAPS (already using secure connection) and TLS do not work together. Switched off TLS.',
\OCP\Util::INFO);
}
//second step: critical checks. If left empty or filled wrong, set as unconfigured and give a warning.
$configurationOK = true;
if(empty($this->config['ldapHost'])) {
\OCP\Util::writeLog('user_ldap', 'No LDAP host given, won`t connect.', \OCP\Util::WARN);
$configurationOK = false;
}
if(empty($this->config['ldapPort'])) {
\OCP\Util::writeLog('user_ldap', 'No LDAP Port given, won`t connect.', \OCP\Util::WARN);
$configurationOK = false;
}
if((empty($this->config['ldapAgentName']) && !empty($this->config['ldapAgentPassword']))
|| (!empty($this->config['ldapAgentName']) && empty($this->config['ldapAgentPassword']))) {
\OCP\Util::writeLog('user_ldap',
'Either no password given for the user agent or a password is given, but no LDAP agent; won`t connect.',
\OCP\Util::WARN);
$configurationOK = false;
}
//TODO: check if ldapAgentName is in DN form
if(empty($this->config['ldapBase'])
&& (empty($this->config['ldapBaseUsers'])
&& empty($this->config['ldapBaseGroups']))) {
\OCP\Util::writeLog('user_ldap', 'No Base DN given, won`t connect.', \OCP\Util::WARN);
$configurationOK = false;
}
if(empty($this->config['ldapUserDisplayName'])) {
\OCP\Util::writeLog('user_ldap',
'No user display name attribute specified, won`t connect.',
\OCP\Util::WARN);
$configurationOK = false;
}
if(empty($this->config['ldapGroupDisplayName'])) {
\OCP\Util::writeLog('user_ldap',
'No group display name attribute specified, won`t connect.',
\OCP\Util::WARN);
$configurationOK = false;
}
if(empty($this->config['ldapLoginFilter'])) {
\OCP\Util::writeLog('user_ldap', 'No login filter specified, won`t connect.', \OCP\Util::WARN);
$configurationOK = false;
}
if(mb_strpos($this->config['ldapLoginFilter'], '%uid', 0, 'UTF-8') === false) {
\OCP\Util::writeLog('user_ldap',
'Login filter does not contain %uid place holder, won`t connect.',
\OCP\Util::WARN);
\OCP\Util::writeLog('user_ldap', 'Login filter was ' . $this->config['ldapLoginFilter'], \OCP\Util::DEBUG);
$configurationOK = false;
}
if(!empty($this->config['ldapExpertUUIDUserAttr'])) {
$this->config['ldapUuidUserAttribute'] = $this->config['ldapExpertUUIDUserAttr'];
}
if(!empty($this->config['ldapExpertUUIDGroupAttr'])) {
$this->config['ldapUuidGroupAttribute'] = $this->config['ldapExpertUUIDGroupAttr'];
}
return $configurationOK;
//second step: critical checks. If left empty or filled wrong, set as
//unconfigured and give a warning.
return $this->doCriticalValidation();
}
/**
* @returns an associative array with the default values. Keys are correspond
* to config-value entries in the database table
*/
static public function getDefaults() {
return array(
'ldap_host' => '',
'ldap_port' => '389',
'ldap_backup_host' => '',
'ldap_backup_port' => '',
'ldap_override_main_server' => '',
'ldap_dn' => '',
'ldap_agent_password' => '',
'ldap_base' => '',
'ldap_base_users' => '',
'ldap_base_groups' => '',
'ldap_userlist_filter' => 'objectClass=person',
'ldap_login_filter' => 'uid=%uid',
'ldap_group_filter' => 'objectClass=posixGroup',
'ldap_display_name' => 'cn',
'ldap_group_display_name' => 'cn',
'ldap_tls' => 1,
'ldap_nocase' => 0,
'ldap_quota_def' => '',
'ldap_quota_attr' => '',
'ldap_email_attr' => '',
'ldap_group_member_assoc_attribute' => 'uniqueMember',
'ldap_cache_ttl' => 600,
'ldap_uuid_user_attribute' => 'auto',
'ldap_uuid_group_attribute' => 'auto',
'ldap_override_uuid_attribute' => 0,
'home_folder_naming_rule' => '',
'ldap_turn_off_cert_check' => 0,
'ldap_configuration_active' => 1,
'ldap_attributes_for_user_search' => '',
'ldap_attributes_for_group_search' => '',
'ldap_expert_username_attr' => '',
'ldap_expert_uuid_user_attr' => '',
'ldap_expert_uuid_group_attr' => '',
);
}
/**
* Connects and Binds to LDAP
*/
private function establishConnection() {
if(!$this->config['ldapConfigurationActive']) {
if(!$this->configuration->ldapConfigurationActive) {
return null;
}
static $phpLDAPinstalled = true;
@ -632,29 +423,36 @@ class Connection extends LDAPUtility {
return false;
}
if(!$this->configured) {
\OCP\Util::writeLog('user_ldap', 'Configuration is invalid, cannot connect', \OCP\Util::WARN);
\OCP\Util::writeLog('user_ldap',
'Configuration is invalid, cannot connect',
\OCP\Util::WARN);
return false;
}
if(!$this->ldapConnectionRes) {
if(!$this->ldap->areLDAPFunctionsAvailable()) {
$phpLDAPinstalled = false;
\OCP\Util::writeLog('user_ldap',
'function ldap_connect is not available. Make sure that the PHP ldap module is installed.',
\OCP\Util::ERROR);
'function ldap_connect is not available. Make '.
'sure that the PHP ldap module is installed.',
\OCP\Util::ERROR);
return false;
}
if($this->config['turnOffCertCheck']) {
if($this->configuration->turnOffCertCheck) {
if(putenv('LDAPTLS_REQCERT=never')) {
\OCP\Util::writeLog('user_ldap',
'Turned off SSL certificate validation successfully.',
\OCP\Util::WARN);
} else {
\OCP\Util::writeLog('user_ldap', 'Could not turn off SSL certificate validation.', \OCP\Util::WARN);
\OCP\Util::writeLog('user_ldap',
'Could not turn off SSL certificate validation.',
\OCP\Util::WARN);
}
}
if(!$this->config['ldapOverrideMainServer'] && !$this->getFromCache('overrideMainServer')) {
$this->doConnect($this->config['ldapHost'], $this->config['ldapPort']);
if(!$this->configuration->ldapOverrideMainServer
&& !$this->getFromCache('overrideMainServer')) {
$this->doConnect($this->configuration->ldapHost,
$this->configuration->ldapPort);
$bindStatus = $this->bind();
$error = $this->ldap->isResource($this->ldapConnectionRes) ?
$this->ldap->errno($this->ldapConnectionRes) : -1;
@ -665,9 +463,10 @@ class Connection extends LDAPUtility {
//if LDAP server is not reachable, try the Backup (Replica!) Server
if((!$bindStatus && ($error !== 0))
|| $this->config['ldapOverrideMainServer']
|| $this->configuration->ldapOverrideMainServer
|| $this->getFromCache('overrideMainServer')) {
$this->doConnect($this->config['ldapBackupHost'], $this->config['ldapBackupPort']);
$this->doConnect($this->configuration->ldapBackupHost,
$this->configuration->ldapBackupPort);
$bindStatus = $this->bind();
if(!$bindStatus && $error === -1) {
//when bind to backup server succeeded and failed to main server,
@ -690,7 +489,7 @@ class Connection extends LDAPUtility {
$this->ldapConnectionRes = $this->ldap->connect($host, $port);
if($this->ldap->setOption($this->ldapConnectionRes, LDAP_OPT_PROTOCOL_VERSION, 3)) {
if($this->ldap->setOption($this->ldapConnectionRes, LDAP_OPT_REFERRALS, 0)) {
if($this->config['ldapTLS']) {
if($this->configuration->ldapTLS) {
$this->ldap->startTls($this->ldapConnectionRes);
}
}
@ -702,7 +501,7 @@ class Connection extends LDAPUtility {
*/
public function bind() {
static $getConnectionResourceAttempt = false;
if(!$this->config['ldapConfigurationActive']) {
if(!$this->configuration->ldapConfigurationActive) {
return false;
}
if($getConnectionResourceAttempt) {
@ -716,8 +515,8 @@ class Connection extends LDAPUtility {
return false;
}
$ldapLogin = @$this->ldap->bind($cr,
$this->config['ldapAgentName'],
$this->config['ldapAgentPassword']);
$this->configuration->ldapAgentName,
$this->configuration->ldapAgentPassword);
if(!$ldapLogin) {
\OCP\Util::writeLog('user_ldap',
'Bind failed: ' . $this->ldap->errno($cr) . ': ' . $this->ldap->error($cr),

View File

@ -161,4 +161,25 @@ class Helper {
return true;
}
/**
* @brief extractsthe domain from a given URL
* @param $url the URL
* @return mixed, domain as string on success, false otherwise
*/
static public function getDomainFromURL($url) {
$uinfo = parse_url($url);
if(!is_array($uinfo)) {
return false;
}
$domain = false;
if(isset($uinfo['host'])) {
$domain = $uinfo['host'];
} else if(isset($uinfo['path'])) {
$domain = $uinfo['path'];
}
return $domain;
}
}

View File

@ -67,6 +67,14 @@ interface ILDAPWrapper {
*/
public function controlPagedResultResponse($link, $result, &$cookie);
/**
* @brief Count the number of entries in a search
* @param $link LDAP link resource
* @param $result LDAP result resource
* @return mixed, number of results on success, false otherwise
*/
public function countEntries($link, $result);
/**
* @brief Return the LDAP error number of the last LDAP command
* @param $link LDAP link resource
@ -97,6 +105,14 @@ interface ILDAPWrapper {
* */
public function getAttributes($link, $result);
/**
* @brief Get the DN of a result entry
* @param $link LDAP link resource
* @param $result LDAP result resource
* @return string containing the DN, false on error
*/
public function getDN($link, $result);
/**
* @brief Get all result entries
* @param $link LDAP link resource
@ -105,6 +121,14 @@ interface ILDAPWrapper {
*/
public function getEntries($link, $result);
/**
* @brief Return next result id
* @param $link LDAP link resource
* @param $result LDAP entry result resource
* @return an LDAP search result resource
* */
public function nextEntry($link, $result);
/**
* @brief Read an entry
* @param $link LDAP link resource

View File

@ -49,6 +49,10 @@ class LDAP implements ILDAPWrapper {
$isCritical, $cookie);
}
public function countEntries($link, $result) {
return $this->invokeLDAPMethod('count_entries', $link, $result);
}
public function errno($link) {
return $this->invokeLDAPMethod('errno', $link);
}
@ -65,10 +69,18 @@ class LDAP implements ILDAPWrapper {
return $this->invokeLDAPMethod('get_attributes', $link, $result);
}
public function getDN($link, $result) {
return $this->invokeLDAPMethod('get_dn', $link, $result);
}
public function getEntries($link, $result) {
return $this->invokeLDAPMethod('get_entries', $link, $result);
}
public function nextEntry($link, $result) {
return $this->invokeLDAPMethod('next_entry', $link, $result);
}
public function read($link, $baseDN, $filter, $attr) {
return $this->invokeLDAPMethod('read', $link, $baseDN, $filter, $attr);
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,58 @@
<?php
/**
* ownCloud LDAP Wizard Result
*
* @author Arthur Schiwon
* @copyright 2013 Arthur Schiwon blizzz@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/>.
*
*/
namespace OCA\user_ldap\lib;
class WizardResult {
protected $changes = array();
protected $options = array();
protected $markedChange = false;
public function addChange($key, $value) {
$this->changes[$key] = $value;
}
public function markChange() {
$this->markedChange = true;
}
public function addOptions($key, $values) {
if(!is_array($values)) {
$values = array($values);
}
$this->options[$key] = $values;
}
public function hasChanges() {
return (count($this->changes) > 0 || $this->markedChange);
}
public function getResultArray() {
$result = array();
$result['changes'] = $this->changes;
if(count($this->options) > 0) {
$result['options'] = $this->options;
}
return $result;
}
}

View File

@ -25,19 +25,50 @@
OC_Util::checkAdminUser();
OCP\Util::addscript('user_ldap', 'settings');
OCP\Util::addstyle('user_ldap', 'settings');
OCP\Util::addScript('user_ldap', 'settings');
OCP\Util::addScript('core', 'jquery.multiselect');
OCP\Util::addStyle('user_ldap', 'settings');
OCP\Util::addStyle('core', 'jquery.multiselect');
OCP\Util::addStyle('core', 'jquery-ui-1.10.0.custom');
// fill template
$tmpl = new OCP\Template('user_ldap', 'settings');
$prefixes = \OCA\user_ldap\lib\Helper::getServerConfigurationPrefixes();
$hosts = \OCA\user_ldap\lib\Helper::getServerConfigurationHosts();
$tmpl->assign('serverConfigurationPrefixes', $prefixes);
$tmpl->assign('serverConfigurationHosts', $hosts);
$wizardHtml = '';
$toc = array();
$wControls = new OCP\Template('user_ldap', 'part.wizardcontrols');
$wControls = $wControls->fetchPage();
$sControls = new OCP\Template('user_ldap', 'part.settingcontrols');
$sControls = $sControls->fetchPage();
$wizTabs = array();
$wizTabs[] = array('tpl' => 'part.wizard-server', 'cap' => 'Server');
$wizTabs[] = array('tpl' => 'part.wizard-userfilter', 'cap' => 'User Filter');
$wizTabs[] = array('tpl' => 'part.wizard-loginfilter', 'cap' => 'Login Filter');
$wizTabs[] = array('tpl' => 'part.wizard-groupfilter', 'cap' => 'Group Filter');
for($i = 0; $i < count($wizTabs); $i++) {
$tab = new OCP\Template('user_ldap', $wizTabs[$i]['tpl']);
if($i === 0) {
$tab->assign('serverConfigurationPrefixes', $prefixes);
$tab->assign('serverConfigurationHosts', $hosts);
}
$tab->assign('wizardControls', $wControls);
$wizardHtml .= $tab->fetchPage();
$toc['#ldapWizard'.($i+1)] = $wizTabs[$i]['cap'];
}
$tmpl->assign('tabs', $wizardHtml);
$tmpl->assign('toc', $toc);
$tmpl->assign('settingControls', $sControls);
// assign default values
$defaults = \OCA\user_ldap\lib\Connection::getDefaults();
$config = new \OCA\user_ldap\lib\Configuration('', false);
$defaults = $config->getDefaults();
foreach($defaults as $key => $default) {
$tmpl->assign($key.'_default', $default);
}

View File

@ -0,0 +1,12 @@
<div class="ldapSettingControls">
<input id="ldap_submit" type="submit" value="Save" />
<button id="ldap_action_test_connection" name="ldap_action_test_connection">
<?php p($l->t('Test Configuration'));?>
</button>
<a href="<?php p($theme->getDocBaseUrl()); ?>/server/5.0/admin_manual/auth_ldap.html"
target="_blank">
<img src="<?php print_unescaped(OCP\Util::imagePath('', 'actions/info.png')); ?>"
style="height:1.75ex" />
<?php p($l->t('Help'));?>
</a>
</div>

View File

@ -0,0 +1,42 @@
<fieldset id="ldapWizard4">
<div>
<p>
<?php p($l->t('Limit the access to %s to groups meeting this criteria:', $theme->getName()));?>
</p>
<p>
<label for="ldap_groupfilter_objectclass">
<?php p($l->t('only those object classes:'));?>
</label>
<select id="ldap_groupfilter_objectclass" multiple="multiple"
name="ldap_groupfilter_objectclass">
</select>
</p>
<p>
<label for="ldap_groupfilter_groups">
<?php p($l->t('only from those groups:'));?>
</label>
<select id="ldap_groupfilter_groups" multiple="multiple"
name="ldap_groupfilter_groups">
</select>
</p>
<p>
<label><a id='toggleRawGroupFilter'> <?php p($l->t('Edit raw filter instead'));?></a></label>
</p>
<p id="rawGroupFilterContainer" class="invisible">
<input type="text" id="ldap_group_filter" name="ldap_group_filter"
class="lwautosave"
placeholder="<?php p($l->t('Raw LDAP filter'));?>"
title="<?php p($l->t('The filter specifies which LDAP groups shall have access to the %s instance.', $theme->getName()));?>"
/>
</p>
<p>
<div class="ldapWizardInfo invisible">&nbsp;</div>
</p>
<p>
<span id="ldap_group_count">0 <?php p($l->t('groups found'));?></span>
</p>
<?php print_unescaped($_['wizardControls']); ?>
</div>
</fieldset>

View File

@ -0,0 +1,37 @@
<fieldset id="ldapWizard3">
<div>
<p>
<?php p($l->t('What attribute shall be used as login name:'));?>
</p>
<p>
<label for="ldap_loginfilter_username">
<?php p($l->t('LDAP Username:'));?>
</label>
<input type="checkbox" id="ldap_loginfilter_username"
name="ldap_loginfilter_username" value="1" class="lwautosave" />
</p>
<p>
<label for="ldap_loginfilter_email">
<?php p($l->t('LDAP Email Address:'));?>
</label>
<input type="checkbox" id="ldap_loginfilter_email"
name="ldap_loginfilter_email" value="1" class="lwautosave" />
</p>
<p>
<label for="ldap_loginfilter_attributes">
<?php p($l->t('Other Attributes:'));?>
</label>
<select id="ldap_loginfilter_attributes" multiple="multiple"
name="ldap_loginfilter_attributes">
</select>
</p>
<p>
<div class="ldapWizardInfo invisible">&nbsp;</div>
</p>
<?php print_unescaped($_['wizardControls']); ?>
</div>
</fieldset>

View File

@ -0,0 +1,71 @@
<fieldset id="ldapWizard1">
<p>
<select id="ldap_serverconfig_chooser" name="ldap_serverconfig_chooser">
<?php if(count($_['serverConfigurationPrefixes']) === 0 ) {
?>
<option value="" selected>1. Server</option>');
<?php
} else {
$i = 1;
$sel = ' selected';
foreach($_['serverConfigurationPrefixes'] as $prefix) {
?>
<option value="<?php p($prefix); ?>"<?php p($sel); $sel = ''; ?>><?php p($i++); ?>. Server: <?php p($_['serverConfigurationHosts'][$prefix]); ?></option>
<?php
}
}
?>
<option value="NEW"><?php p($l->t('Add Server Configuration'));?></option>
</select>
<button id="ldap_action_delete_configuration"
name="ldap_action_delete_configuration">Delete Configuration</button>
</p>
<div class="hostPortCombinator">
<div class="tablerow">
<div class="tablecell">
<div class="table">
<input type="text" class="host tablecell lwautosave" id="ldap_host"
name="ldap_host"
placeholder="<?php p($l->t('Host'));?>"
title="<?php p($l->t('You can omit the protocol, except you require SSL. Then start with ldaps://'));?>"
/>
<span>
<input type="number" id="ldap_port" name="ldap_port"
class="invisible lwautosave"
placeholder="<?php p($l->t('Port'));?>" />
</span>
</div>
</div>
</div>
<div class="tablerow">
<input type="text" id="ldap_dn" name="ldap_dn"
class="tablecell lwautosave"
placeholder="<?php p($l->t('User DN'));?>"
title="<?php p($l->t('The DN of the client user with which the bind shall be done, e.g. uid=agent,dc=example,dc=com. For anonymous access, leave DN and Password empty.'));?>"
/>
</div>
<div class="tablerow">
<input type="password" id="ldap_agent_password"
class="tablecell lwautosave" name="ldap_agent_password"
placeholder="<?php p($l->t('Password'));?>"
title="<?php p($l->t('For anonymous access, leave DN and Password empty.'));?>"
/>
</div>
<div class="tablerow">
<textarea id="ldap_base" name="ldap_base"
class="tablecell invisible lwautosave"
placeholder="<?php p($l->t('One Base DN per line'));?>"
title="<?php p($l->t('You can specify Base DN for users and groups in the Advanced tab'));?>">
</textarea>
</div>
<div class="tablerow">
<div class="tablecell ldapWizardInfo invisible">&nbsp;
</div>
</div>
</div>
<?php print_unescaped($_['wizardControls']); ?>
</fieldset>

View File

@ -0,0 +1,42 @@
<fieldset id="ldapWizard2">
<div>
<p>
<?php p($l->t('Limit the access to %s to users meeting this criteria:', $theme->getName()));?>
</p>
<p>
<label for="ldap_userfilter_objectclass">
<?php p($l->t('only those object classes:'));?>
</label>
<select id="ldap_userfilter_objectclass" multiple="multiple"
name="ldap_userfilter_objectclass">
</select>
</p>
<p>
<label for="ldap_userfilter_groups">
<?php p($l->t('only from those groups:'));?>
</label>
<select id="ldap_userfilter_groups" multiple="multiple"
name="ldap_userfilter_groups">
</select>
</p>
<p>
<label><a id='toggleRawUserFilter'> <?php p($l->t('Edit raw filter instead'));?></a></label>
</p>
<p id="rawUserFilterContainer" class="invisible">
<input type="text" id="ldap_userlist_filter" name="ldap_userlist_filter"
class="lwautosave"
placeholder="<?php p($l->t('Raw LDAP filter'));?>"
title="<?php p($l->t('The filter specifies which LDAP users shall have access to the %s instance.', $theme->getName()));?>"
/>
</p>
<p>
<div class="ldapWizardInfo invisible">&nbsp;</div>
</p>
<p>
<span id="ldap_user_count">0 <?php p($l->t('users found'));?></span>
</p>
<?php print_unescaped($_['wizardControls']); ?>
</div>
</fieldset>

View File

@ -0,0 +1,15 @@
<div class="ldapWizardControls">
<button class="ldap_action_back invisible" name="ldap_action_back"
type="button">
<?php p($l->t('Back'));?>
</button>
<button class="ldap_action_continue" name="ldap_action_continue" type="button">
<?php p($l->t('Continue'));?>
</button>
<a href="<?php p($theme->getDocBaseUrl()); ?>/server/5.0/admin_manual/auth_ldap.html"
target="_blank">
<img src="<?php print_unescaped(OCP\Util::imagePath('', 'actions/info.png')); ?>"
style="height:1.75ex" />
<?php p($l->t('Help'));?>
</a>
</div>

View File

@ -1,9 +1,11 @@
<form id="ldap" action="#" method="post">
<div id="ldapSettings" class="personalblock">
<ul>
<li><a href="#ldapSettings-1">LDAP Basic</a></li>
<li><a href="#ldapSettings-2">Advanced</a></li>
<li><a href="#ldapSettings-3">Expert</a></li>
<?php foreach($_['toc'] as $id => $title) { ?>
<li id="<?php p($id); ?>"><a href="<?php p($id); ?>"><?php p($title); ?></a></li>
<?php } ?>
<li class="ldapSettingsTabs"><a href="#ldapSettings-2">Expert</a></li>
<li class="ldapSettingsTabs"><a href="#ldapSettings-1">Advanced</a></li>
</ul>
<?php if(OCP\App::isEnabled('user_webdavauth')) {
print_unescaped('<p class="ldapwarning">'.$l->t('<b>Warning:</b> Apps user_ldap and user_webdavauth are incompatible. You may experience unexpected behavior. Please ask your system administrator to disable one of them.').'</p>');
@ -12,65 +14,19 @@
print_unescaped('<p class="ldapwarning">'.$l->t('<b>Warning:</b> The PHP LDAP module is not installed, the backend will not work. Please ask your system administrator to install it.').'</p>');
}
?>
<?php print_unescaped($_['tabs']); ?>
<fieldset id="ldapSettings-1">
<p><label for="ldap_serverconfig_chooser"><?php p($l->t('Server configuration'));?></label>
<select id="ldap_serverconfig_chooser" name="ldap_serverconfig_chooser">
<?php if(count($_['serverConfigurationPrefixes']) === 0 ) {
?>
<option value="" selected>1. Server</option>');
<?php
} else {
$i = 1;
$sel = ' selected';
foreach($_['serverConfigurationPrefixes'] as $prefix) {
?>
<option value="<?php p($prefix); ?>"<?php p($sel); $sel = ''; ?>><?php p($i++); ?>. Server: <?php p($_['serverConfigurationHosts'][$prefix]); ?></option>
<?php
}
}
?>
<option value="NEW"><?php p($l->t('Add Server Configuration'));?></option>
</select>
<button id="ldap_action_delete_configuration"
name="ldap_action_delete_configuration">Delete Configuration</button>
</p>
<p><label for="ldap_host"><?php p($l->t('Host'));?></label>
<input type="text" id="ldap_host" name="ldap_host" data-default="<?php p($_['ldap_host_default']); ?>"
title="<?php p($l->t('You can omit the protocol, except you require SSL. Then start with ldaps://'));?>"></p>
<p><label for="ldap_base"><?php p($l->t('Base DN'));?></label>
<textarea id="ldap_base" name="ldap_base" placeholder="<?php p($l->t('One Base DN per line'));?>"
title="<?php p($l->t('You can specify Base DN for users and groups in the Advanced tab'));?>"
data-default="<?php p($_['ldap_base_default']); ?>" ></textarea></p>
<p><label for="ldap_dn"><?php p($l->t('User DN'));?></label>
<input type="text" id="ldap_dn" name="ldap_dn" data-default="<?php p($_['ldap_dn_default']); ?>"
title="<?php p($l->t('The DN of the client user with which the bind shall be done, e.g. uid=agent,dc=example,dc=com. For anonymous access, leave DN and Password empty.'));?>" /></p>
<p><label for="ldap_agent_password"><?php p($l->t('Password'));?></label>
<input type="password" id="ldap_agent_password" name="ldap_agent_password"
data-default="<?php p($_['ldap_agent_password_default']); ?>"
title="<?php p($l->t('For anonymous access, leave DN and Password empty.'));?>" /></p>
<p><label for="ldap_login_filter"><?php p($l->t('User Login Filter'));?></label>
<input type="text" id="ldap_login_filter" name="ldap_login_filter"
data-default="<?php p($_['ldap_login_filter_default']); ?>"
title="<?php p($l->t('Defines the filter to apply, when login is attempted. %%uid replaces the username in the login action. Example: "uid=%%uid"'));?>" /></p>
<p><label for="ldap_userlist_filter"><?php p($l->t('User List Filter'));?></label>
<input type="text" id="ldap_userlist_filter" name="ldap_userlist_filter"
data-default="<?php p($_['ldap_userlist_filter_default']); ?>"
title="<?php p($l->t('Defines the filter to apply, when retrieving users (no placeholders). Example: "objectClass=person"'));?>" /></p>
<p><label for="ldap_group_filter"><?php p($l->t('Group Filter'));?></label>
<input type="text" id="ldap_group_filter" name="ldap_group_filter"
data-default="<?php p($_['ldap_group_filter_default']); ?>"
title="<?php p($l->t('Defines the filter to apply, when retrieving groups (no placeholders). Example: "objectClass=posixGroup"'));?>" /></p>
</fieldset>
<fieldset id="ldapSettings-2">
<div id="ldapAdvancedAccordion">
<h3><?php p($l->t('Connection Settings'));?></h3>
<div>
<p><label for="ldap_configuration_active"><?php p($l->t('Configuration Active'));?></label><input type="checkbox" id="ldap_configuration_active" name="ldap_configuration_active" value="1" data-default="<?php p($_['ldap_configuration_active_default']); ?>" title="<?php p($l->t('When unchecked, this configuration will be skipped.'));?>" /></p>
<p><label for="ldap_port"><?php p($l->t('Port'));?></label><input type="number" id="ldap_port" name="ldap_port" data-default="<?php p($_['ldap_port_default']); ?>" /></p>
<p><label for="ldap_login_filter"><?php p($l->t('User Login Filter'));?></label>
<input type="text" id="ldap_login_filter" name="ldap_login_filter"
data-default="<?php p($_['ldap_login_filter_default']); ?>"
title="<?php p($l->t('Defines the filter to apply, when login is attempted. %%uid replaces the username in the login action. Example: "uid=%%uid"'));?>" /></p>
<p><label for="ldap_backup_host"><?php p($l->t('Backup (Replica) Host'));?></label><input type="text" id="ldap_backup_host" name="ldap_backup_host" data-default="<?php p($_['ldap_backup_host_default']); ?>" title="<?php p($l->t('Give an optional backup host. It must be a replica of the main LDAP/AD server.'));?>"></p>
<p><label for="ldap_backup_port"><?php p($l->t('Backup (Replica) Port'));?></label><input type="number" id="ldap_backup_port" name="ldap_backup_port" data-default="<?php p($_['ldap_backup_port_default']); ?>" /></p>
<p><label for="ldap_override_main_server"><?php p($l->t('Disable Main Server'));?></label><input type="checkbox" id="ldap_override_main_server" name="ldap_override_main_server" value="1" data-default="<?php p($_['ldap_override_main_server_default']); ?>" title="<?php p($l->t('Only connect to the replica server.'));?>" /></p>
<p><label for="ldap_tls"><?php p($l->t('Use TLS'));?></label><input type="checkbox" id="ldap_tls" name="ldap_tls" value="1" data-default="<?php p($_['ldap_tls_default']); ?>" title="<?php p($l->t('Do not use it additionally for LDAPS connections, it will fail.'));?>" /></p>
<p><label for="ldap_nocase"><?php p($l->t('Case insensitve LDAP server (Windows)'));?></label><input type="checkbox" id="ldap_nocase" name="ldap_nocase" data-default="<?php p($_['ldap_nocase_default']); ?>" value="1"<?php if (isset($_['ldap_nocase']) && ($_['ldap_nocase'])) p(' checked'); ?>></p>
<p><label for="ldap_turn_off_cert_check"><?php p($l->t('Turn off SSL certificate validation.'));?></label><input type="checkbox" id="ldap_turn_off_cert_check" name="ldap_turn_off_cert_check" title="<?php p($l->t('Not recommended, use it for testing only! If connection only works with this option, import the LDAP server\'s SSL certificate in your %s server.', $theme->getName() ));?>" data-default="<?php p($_['ldap_turn_off_cert_check_default']); ?>" value="1"><br/></p>
<p><label for="ldap_cache_ttl"><?php p($l->t('Cache Time-To-Live'));?></label><input type="number" id="ldap_cache_ttl" name="ldap_cache_ttl" title="<?php p($l->t('in seconds. A change empties the cache.'));?>" data-default="<?php p($_['ldap_cache_ttl_default']); ?>" /></p>
@ -93,8 +49,9 @@
<p><label for="home_folder_naming_rule"><?php p($l->t('User Home Folder Naming Rule'));?></label><input type="text" id="home_folder_naming_rule" name="home_folder_naming_rule" title="<?php p($l->t('Leave empty for user name (default). Otherwise, specify an LDAP/AD attribute.'));?>" data-default="<?php p($_['home_folder_naming_rule_default']); ?>" /></p>
</div>
</div>
<?php print_unescaped($_['settingControls']); ?>
</fieldset>
<fieldset id="ldapSettings-3">
<fieldset id="ldapSettings-2">
<p><strong><?php p($l->t('Internal Username'));?></strong></p>
<p class="ldapIndent"><?php p($l->t('By default the internal username will be created from the UUID attribute. It makes sure that the username is unique and characters do not need to be converted. The internal username has the restriction that only these characters are allowed: [ a-zA-Z0-9_.@- ]. Other characters are replaced with their ASCII correspondence or simply omitted. On collisions a number will be added/increased. The internal username is used to identify a user internally. It is also the default name for the user home folder. It is also a part of remote URLs, for instance for all *DAV services. With this setting, the default behavior can be overridden. To achieve a similar behavior as before ownCloud 5 enter the user display name attribute in the following field. Leave it empty for default behavior. Changes will have effect only on newly mapped (added) LDAP users.'));?></p>
<p class="ldapIndent"><label for="ldap_expert_username_attr"><?php p($l->t('Internal Username Attribute:'));?></label><input type="text" id="ldap_expert_username_attr" name="ldap_expert_username_attr" data-default="<?php p($_['ldap_expert_username_attr_default']); ?>" /></p>
@ -105,8 +62,8 @@
<p><strong><?php p($l->t('Username-LDAP User Mapping'));?></strong></p>
<p class="ldapIndent"><?php p($l->t('Usernames are used to store and assign (meta) data. In order to precisely identify and recognize users, each LDAP user will have a internal username. This requires a mapping from username to LDAP user. The created username is mapped to the UUID of the LDAP user. Additionally the DN is cached as well to reduce LDAP interaction, but it is not used for identification. If the DN changes, the changes will be found. The internal username is used all over. Clearing the mappings will have leftovers everywhere. Clearing the mappings is not configuration sensitive, it affects all LDAP configurations! Never clear the mappings in a production environment, only in a testing or experimental stage.'));?></p>
<p class="ldapIndent"><button id="ldap_action_clear_user_mappings" name="ldap_action_clear_user_mappings"><?php p($l->t('Clear Username-LDAP User Mapping'));?></button><br/><button id="ldap_action_clear_group_mappings" name="ldap_action_clear_group_mappings"><?php p($l->t('Clear Groupname-LDAP Group Mapping'));?></button></p>
<?php print_unescaped($_['settingControls']); ?>
</fieldset>
<input id="ldap_submit" type="submit" value="Save" /> <button id="ldap_action_test_connection" name="ldap_action_test_connection"><?php p($l->t('Test Configuration'));?></button> <a href="<?php print_unescaped(link_to_docs('admin-ldap')); ?>" target="_blank"><img src="<?php print_unescaped(OCP\Util::imagePath('', 'actions/info.png')); ?>" style="height:1.75ex" /> <?php p($l->t('Help'));?></a>
</div>
</form>

View File

@ -21,28 +21,41 @@
padding:.5em;
}
#shareWithList li {
padding-top:.1em;
}
#shareWithList li {
padding-top: 10px;
padding-bottom: 10px;
font-weight: bold;
line-height: 21px;
white-space: normal;
}
#shareWithList li:first-child {
white-space:normal;
}
#shareWithList .cruds {
margin-left:-10px;
}
#shareWithList .unshare img, #shareWithList .showCruds img {
vertical-align:text-bottom; /* properly align icons */
}
#shareWithList .unshare img, #shareWithList .showCruds img {
vertical-align:text-bottom; /* properly align icons */
}
#shareWithList label input[type=checkbox]{
margin-left: 0;
}
#shareWithList .username{
padding-right: .5em;
white-space: nowrap;
text-overflow: ellipsis;
max-width: 254px;
display: inline-block;
overflow: hidden;
vertical-align: middle;
}
#shareWithList li label{
margin-right: .5em;
}
#dropdown label {
font-weight:400;
white-space: nowrap;
}
#dropdown input[type="checkbox"] {
margin:0 .2em 0 .5em;
vertical-align: middle;
}
a.showCruds {
@ -99,3 +112,9 @@ a.showCruds:hover,a.unshare:hover {
overflow-y:auto;
overflow-x:hidden;
}
.notCreatable {
padding-left: 12px;
padding-top: 12px;
color: #999;
}

View File

@ -202,7 +202,7 @@ input[type="submit"].enabled {
-moz-box-sizing:border-box; box-sizing:border-box;
}
#leftcontent, .leftcontent {
position:relative; overflow:auto; width:20em; height:100%;
position:relative; overflow:auto; width:256px; height:100%;
background:#f8f8f8; border-right:1px solid #ddd;
-moz-box-sizing:border-box; box-sizing:border-box;
}
@ -211,7 +211,11 @@ input[type="submit"].enabled {
#leftcontent li.active, .leftcontent li.active { font-weight:bold; }
#leftcontent li:hover, .leftcontent li:hover { color:#333; background:#ddd; }
#leftcontent a { height:100%; display:block; margin:0; padding:0 1em 0 0; float:left; }
#rightcontent, .rightcontent { position:fixed; top:6.4em; left:24.5em; overflow:auto }
#rightcontent, .rightcontent { position:fixed; top:89px; left: 336px; overflow:auto }
#controls + .leftcontent{
top: 44px;
}
#emptycontent {
font-size: 1.5em;
@ -441,6 +445,11 @@ label.infield { cursor:text !important; top:1.05em; left:.85em; }
cursor: default;
}
#body-login .update {
text-align: center;
color: #ccc;
}
#body-user .warning, #body-settings .warning {
margin-top: 8px;
padding: 5px;

View File

@ -60,7 +60,7 @@
if (typeof(this.data('user')) !== 'undefined') {
user = this.data('user');
} else {
this.placeholder('x');
this.imageplaceholder('x');
return;
}
}
@ -76,9 +76,9 @@
if (typeof(result) === 'object') {
if (!hidedefault) {
if (result.data && result.data.displayname) {
$div.placeholder(user, result.data.displayname);
$div.imageplaceholder(user, result.data.displayname);
} else {
$div.placeholder(user);
$div.imageplaceholder(user);
}
} else {
$div.hide();

View File

@ -0,0 +1,216 @@
/*
jQuery placeholder plugin
by Andrey Kuzmin, @unsoundscapes
Based on existing plugin http://mths.be/placeholder by @mathias
and this demo http://robertnyman.com/2011/05/02/ by @robertnyman
Adopted to toggle placeholder on user input instead of focus
Released under the MIT license
*/
(function (factory) {
'use strict';
if (typeof define === 'function' && define.amd) {
// AMD. Register as anonymous module.
define(['jquery'], factory)
} else {
// Browser globals.
factory(jQuery)
}
}(function ($) {
'use strict';
var isInputSupported = 'placeholder' in document.createElement('input')
, isTextareaSupported = 'placeholder' in document.createElement('textarea')
, $placeholders = $()
function getAttributes (element) {
// Return an object of element attributes
var newAttrs = {}
, rinlinejQuery = /^jQuery\d+$/
$.each(element.attributes, function () {
if (this.specified && !rinlinejQuery.test(this.name)) {
newAttrs[this.name] = this.value
}
})
return newAttrs
}
function setCaretTo (element, index) {
// Set caret to specified @index
if (element.createTextRange) {
var range = element.createTextRange()
range.move('character', index)
range.select()
} else if (element.selectionStart !== null) {
element.focus()
element.setSelectionRange(index, index)
}
}
function Placeholder (element, options) {
this.options = options || {}
this.$replacement = this.$element = $(element)
this.initialize.apply(this, arguments)
// Cache all elements with placeholders
$placeholders = $placeholders.add(element)
}
Placeholder.prototype = {
initialize: function () {
this.isHidden = true
this.placeholderAttr = this.$element.attr('placeholder')
// do not mess with default behavior
this.$element.removeAttr('placeholder')
this.isPassword = this.$element.is('[type=password]')
if (this.isPassword) this.makeReplacement()
this.$replacement.on({
'keydown.placeholder': $.proxy(this.hide, this)
, 'focus.placeholder drop.placeholder click.placeholder': $.proxy(this.setCaret, this)
})
this.$element.on({
'blur.placeholder keyup.placeholder': $.proxy(this.show, this)
})
this.show()
}
// Set or get input value
// Setting value toggles placeholder
, val: function (value) {
if (value === undefined) {
return this.isHidden ? this.$element[0].value : '';
}
if (value === '') {
if (this.isHidden) {
this.$element[0].value = value
this.show()
}
} else {
if (!this.isHidden) this.hide()
this.$element[0].value = value
}
return this
}
// Hide placeholder at user input
, hide: function (e) {
var isActiveElement = this.$replacement.is(':focus')
if (this.isHidden) return;
if (!e || !(e.shiftKey && e.keyCode === 16) && e.keyCode !== 9) {
this.isHidden = true
if (this.isPassword) {
this.$replacement.before(this.$element.show()).hide()
if (isActiveElement) this.$element.focus()
} else {
this.$element[0].value = ''
this.$element.removeClass(this.options.className)
}
}
}
// Show placeholder on blur and keyup
, show: function (e) {
var isActiveElement = this.$element.is(':focus')
if (!this.isHidden) return;
if (this.$element[0].value === '') {
this.isHidden = false
if (this.isPassword) {
this.$element.before(this.$replacement.show()).hide()
if (isActiveElement) this.$replacement.focus()
} else {
this.$element[0].value = this.placeholderAttr
this.$element.addClass(this.options.className)
if (isActiveElement) this.setCaret(e)
}
}
}
// Set caret at the beginning of the input
, setCaret: function (e) {
if (e && !this.isHidden) {
setCaretTo(this.$replacement[0], 0)
e.preventDefault()
}
}
// Make and return replacement element
, makeReplacement: function () {
// we can't use $.fn.clone because ie <= 8 doesn't allow type change
var replacementAttributes =
$.extend(
getAttributes(this.$element[0])
, { 'type': 'text'
, 'value': this.placeholderAttr
}
)
// replacement should not have input name
delete replacementAttributes.name
this.$replacement = $('<input>', replacementAttributes)
.data('placeholder', this)
.addClass(this.options.className)
return this.$replacement;
}
}
// Override jQuery val and prop hooks
$.valHooks.input = $.valHooks.textarea = $.propHooks.value = {
get: function (element) {
var placeholder = $(element).data('placeholder')
return placeholder ? placeholder.val() : element.value;
}
, set: function (element, value) {
var placeholder = $(element).data('placeholder')
return placeholder ? placeholder.val(value) : element.value = value;
}
}
// Plugin definition
$.fn.placeholder = function (option) {
return this.each(function () {
var $this = $(this)
, data = $this.data('placeholder')
, options = $.extend({}, $.fn.placeholder.defaults, typeof option === 'object' && option)
if (!data && $this.is('[placeholder]') && (options.force ||
!isInputSupported && $this.is('input') ||
!isTextareaSupported && $this.is('textarea'))) {
$this.data('placeholder', data = new Placeholder(this, options))
}
if (data && typeof option === 'string') data[option]()
})
}
$.fn.placeholder.defaults = {
force: false
, className: 'placeholder'
}
$.fn.placeholder.Constructor = Placeholder
// Events
$(document).on('submit.placeholder', 'form', function () {
// Clear the placeholder values so they don't get submitted
$placeholders.placeholder('hide')
// And then restore them back
setTimeout(function () { $placeholders.placeholder('show') }, 10)
})
$(window).on('beforeunload.placeholder', function () {
// Clear placeholders upon page reload
$placeholders.placeholder('hide')
})
return Placeholder
}));

View File

@ -933,7 +933,7 @@ jQuery.fn.selectRange = function(start, end) {
*/
jQuery.fn.exists = function(){
return this.length > 0;
}
};
/**
* Calls the server periodically every 15 mins to ensure that session doesnt

View File

@ -82,7 +82,7 @@
}
);
} catch(e) {
console.error(e, 'data:', data)
console.error(e, 'data:', data);
}
},
options: {

View File

@ -30,7 +30,7 @@
*
* And call this from Javascript:
*
* $('#albumart').placeholder('The Album Title');
* $('#albumart').imageplaceholder('The Album Title');
*
* Which will result in:
*
@ -38,7 +38,7 @@
*
* You may also call it like this, to have a different background, than the seed:
*
* $('#albumart').placeholder('The Album Title', 'Album Title');
* $('#albumart').imageplaceholder('The Album Title', 'Album Title');
*
* Resulting in:
*
@ -47,7 +47,7 @@
*/
(function ($) {
$.fn.placeholder = function(seed, text) {
$.fn.imageplaceholder = function(seed, text) {
// set optional argument "text" to value of "seed" if undefined
text = text || seed;

View File

@ -200,13 +200,13 @@ OC.Share={
}
});
html += '<input id="shareWith" type="text" placeholder="'+t('core', 'Share with')+'" />';
html += '<input id="shareWith" type="text" placeholder="'+t('core', 'Share with user or group …')+'" />';
html += '<ul id="shareWithList">';
html += '</ul>';
var linksAllowed = $('#allowShareWithLink').val() === 'yes';
if (link && linksAllowed) {
html += '<div id="link">';
html += '<input type="checkbox" name="linkCheckbox" id="linkCheckbox" value="1" /><label for="linkCheckbox">'+t('core', 'Share with link')+'</label>';
html += '<input type="checkbox" name="linkCheckbox" id="linkCheckbox" value="1" /><label for="linkCheckbox">'+t('core', 'Share link')+'</label>';
html += '<br />';
html += '<input id="linkText" type="text" readonly="readonly" />';
html += '<input type="checkbox" name="showPassword" id="showPassword" value="1" style="display:none;" /><label for="showPassword" style="display:none;">'+t('core', 'Password protect')+'</label>';
@ -310,6 +310,9 @@ OC.Share={
$('#dropdown').show('blind', function() {
OC.Share.droppedDown = true;
});
if ($('html').hasClass('lte9')){
$('#dropdown input[placeholder]').placeholder();
}
$('#shareWith').focus();
},
hideDropDown:function(callback) {
@ -363,29 +366,21 @@ OC.Share={
shareChecked = 'checked="checked"';
}
var html = '<li style="clear: both;" data-share-type="'+escapeHTML(shareType)+'" data-share-with="'+escapeHTML(shareWith)+'" title="' + escapeHTML(shareWith) + '">';
html += '<a href="#" class="unshare" style="display:none;"><img class="svg" alt="'+t('core', 'Unshare')+'" src="'+OC.imagePath('core', 'actions/delete')+'"/></a>';
if(shareWith.length > 14){
html += escapeHTML(shareWithDisplayName.substr(0,11) + '...');
}else{
html += escapeHTML(shareWithDisplayName);
}
var showCrudsButton;
html += '<a href="#" class="unshare"><img class="svg" alt="'+t('core', 'Unshare')+'" src="'+OC.imagePath('core', 'actions/delete')+'"/></a>';
html += '<span class="username">' + escapeHTML(shareWithDisplayName) + '</span>';
var mailNotificationEnabled = $('input:hidden[name=mailNotificationEnabled]').val();
if (mailNotificationEnabled === 'yes') {
var checked = '';
if (mailSend === '1') {
checked = 'checked';
}
html += '<label><input type="checkbox" name="mailNotification" class="mailNotification" ' + checked + ' />'+t('core', 'notify user by email')+'</label>';
html += '<label><input type="checkbox" name="mailNotification" class="mailNotification" ' + checked + ' />'+t('core', 'notify by email')+'</label> ';
}
if (possiblePermissions & OC.PERMISSION_CREATE || possiblePermissions & OC.PERMISSION_UPDATE || possiblePermissions & OC.PERMISSION_DELETE) {
if (editChecked == '') {
html += '<label style="display:none;">';
} else {
html += '<label>';
}
html += '<input type="checkbox" name="edit" class="permissions" '+editChecked+' />'+t('core', 'can edit')+'</label>';
html += '<label><input type="checkbox" name="edit" class="permissions" '+editChecked+' />'+t('core', 'can edit')+'</label> ';
}
html += '<a href="#" class="showCruds" style="display:none;"><img class="svg" alt="'+t('core', 'access control')+'" src="'+OC.imagePath('core', 'actions/triangle-s')+'"/></a>';
showCrudsButton = '<a href="#" class="showCruds"><img class="svg" alt="'+t('core', 'access control')+'" src="'+OC.imagePath('core', 'actions/triangle-s')+'"/></a>';
html += '<div class="cruds" style="display:none;">';
if (possiblePermissions & OC.PERMISSION_CREATE) {
html += '<label><input type="checkbox" name="create" class="permissions" '+createChecked+' data-permissions="'+OC.PERMISSION_CREATE+'" />'+t('core', 'create')+'</label>';
@ -401,7 +396,15 @@ OC.Share={
}
html += '</div>';
html += '</li>';
$(html).appendTo('#shareWithList');
html = $(html).appendTo('#shareWithList');
// insert cruds button into last label element
var lastLabel = html.find('>label:last');
if (lastLabel.exists()){
lastLabel.append(showCrudsButton);
}
else{
html.find('.cruds').before(showCrudsButton);
}
$('#expiration').show();
}
},
@ -507,26 +510,8 @@ $(document).ready(function() {
}
});
$(document).on('mouseenter', '#dropdown #shareWithList li', function(event) {
// Show permissions and unshare button
$(':hidden', this).filter(':not(.cruds)').show();
});
$(document).on('mouseleave', '#dropdown #shareWithList li', function(event) {
// Hide permissions and unshare button
if (!$('.cruds', this).is(':visible')) {
$('a', this).hide();
if (!$('input[name="edit"]', this).is(':checked')) {
$('input[type="checkbox"]', this).hide();
$('label', this).hide();
}
} else {
$('a.unshare', this).hide();
}
});
$(document).on('click', '#dropdown .showCruds', function() {
$(this).parent().find('.cruds').toggle();
$(this).closest('li').find('.cruds').toggle();
return false;
});

View File

@ -1,3 +1,3 @@
<div id="{dialog_name}" title="{title}">
<div id="{dialog_name}" title="{title} "><!-- the ' ' after {title} fixes ie8, see http://stackoverflow.com/a/5313137/828717 -->
<p><span class="ui-icon ui-icon-{type}"></span>{message}</p>
</div>

View File

@ -0,0 +1,8 @@
<ul>
<li class='update'>
<?php p($l->t('This ownCloud instance is currently being updated, which may take a while.')) ?><br/><br/>
<?php p($l->t('Please reload this page after a short time to continue using ownCloud.')) ?><br/><br/>
<?php p($l->t('Contact your system administrator if this message persists or appeared unexpectedly.')) ?><br/><br/>
<?php p($l->t('Thank you for your patience.')); ?><br/><br/>
</li>
</ul>

View File

@ -1,30 +0,0 @@
<?php
/**
* ownCloud
*
* @author Frank Karlitschek
* @author Jakob Sack
* @copyright 2012 Frank Karlitschek frank@owncloud.org
* @copyright 2011 Jakob Sack kde@jakobsack.de
*
* 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/>.
*
*/
// only need filesystem apps
$RUNTIME_APPTYPES=array('filesystem', 'authentication');
require_once '../lib/base.php';
$baseuri = OC::$WEBROOT. '/files/webdav.php';
require_once 'apps/files/appinfo/remote.php';

View File

@ -30,8 +30,9 @@ try {
OC::handleRequest();
} catch (Exception $ex) {
\OCP\Util::logException('index', $ex);
//show the user a detailed error page
\OCP\Util::writeLog('index', $ex->getMessage(), \OCP\Util::FATAL);
OC_Response::setStatus(OC_Response::STATUS_INTERNAL_SERVER_ERROR);
OC_Template::printExceptionErrorPage($ex);
}

View File

@ -224,7 +224,9 @@ class OC {
header('Retry-After: 120');
// render error page
OC_Template::printErrorPage('ownCloud is in maintenance mode');
$tmpl = new OC_Template('', 'update.user', 'guest');
$tmpl->printPage();
die();
}
}
@ -240,7 +242,7 @@ class OC {
$minimizerJS = new OC_Minimizer_JS();
$minimizerJS->clearCache();
OC_Util::addscript('update');
$tmpl = new OC_Template('', 'update', 'guest');
$tmpl = new OC_Template('', 'update.admin', 'guest');
$tmpl->assign('version', OC_Util::getVersionString());
$tmpl->printPage();
exit();
@ -259,6 +261,7 @@ class OC {
OC_Util::addScript("jquery-ui-1.10.0.custom");
OC_Util::addScript("jquery-showpassword");
OC_Util::addScript("jquery.infieldlabel");
OC_Util::addScript("jquery.placeholder");
OC_Util::addScript("jquery-tipsy");
OC_Util::addScript("compatibility");
OC_Util::addScript("jquery.ocdialog");
@ -687,7 +690,11 @@ class OC {
}
// Handle WebDAV
if ($_SERVER['REQUEST_METHOD'] == 'PROPFIND') {
header('location: ' . OC_Helper::linkToRemote('webdav'));
// not allowed any more to prevent people
// mounting this root directly.
// Users need to mount remote.php/webdav instead.
header('HTTP/1.1 405 Method Not Allowed');
header('Status: 405 Method Not Allowed');
return;
}

View File

@ -88,8 +88,9 @@ class DIContainer extends SimpleContainer implements IAppContainer{
/**
* Middleware
*/
$this['SecurityMiddleware'] = $this->share(function($c){
return new SecurityMiddleware($this, $c['Request']);
$app = $this;
$this['SecurityMiddleware'] = $this->share(function($c) use ($app){
return new SecurityMiddleware($app, $c['Request']);
});
$middleWares = $this->middleWares;

View File

@ -50,6 +50,10 @@ class OC_Connector_Sabre_Directory extends OC_Connector_Sabre_Node implements Sa
*/
public function createFile($name, $data = null) {
if ($name === 'Shared' && empty($this->path)) {
throw new \Sabre_DAV_Exception_Forbidden();
}
// for chunked upload also updating a existing file is a "createFile"
// because we create all the chunks before reasamble them to the existing file.
if (isset($_SERVER['HTTP_OC_CHUNKED'])) {
@ -82,6 +86,10 @@ class OC_Connector_Sabre_Directory extends OC_Connector_Sabre_Node implements Sa
*/
public function createDirectory($name) {
if ($name === 'Shared' && empty($this->path)) {
throw new \Sabre_DAV_Exception_Forbidden();
}
if (!\OC\Files\Filesystem::isCreatable($this->path)) {
throw new \Sabre_DAV_Exception_Forbidden();
}
@ -187,12 +195,15 @@ class OC_Connector_Sabre_Directory extends OC_Connector_Sabre_Node implements Sa
*/
public function delete() {
if ($this->path === 'Shared') {
throw new \Sabre_DAV_Exception_Forbidden();
}
if (!\OC\Files\Filesystem::isDeletable($this->path)) {
throw new \Sabre_DAV_Exception_Forbidden();
}
if ($this->path != "/Shared") {
\OC\Files\Filesystem::rmdir($this->path);
}
\OC\Files\Filesystem::rmdir($this->path);
}

View File

@ -143,6 +143,10 @@ class OC_Connector_Sabre_File extends OC_Connector_Sabre_Node implements Sabre_D
*/
public function delete() {
if ($this->path === 'Shared') {
throw new \Sabre_DAV_Exception_Forbidden();
}
if (!\OC\Files\Filesystem::isDeletable($this->path)) {
throw new \Sabre_DAV_Exception_Forbidden();
}
@ -218,7 +222,7 @@ class OC_Connector_Sabre_File extends OC_Connector_Sabre_Node implements Sabre_D
if (isset($_SERVER['CONTENT_LENGTH'])) {
$expected = $_SERVER['CONTENT_LENGTH'];
if ($bytesWritten != $expected) {
$chunk_handler->cleanup();
$chunk_handler->remove($info['index']);
throw new Sabre_DAV_Exception_BadRequest(
'expected filesize ' . $expected . ' got ' . $bytesWritten);
}

View File

@ -0,0 +1,73 @@
<?php
/**
* ownCloud
*
* @author Thomas Müller
* @copyright 2013 Thomas Müller <thomas.mueller@tmit.eu>
*
* @license AGPL3
*/
class OC_Connector_Sabre_FilesPlugin extends Sabre_DAV_ServerPlugin
{
// namespace
const NS_OWNCLOUD = 'http://owncloud.org/ns';
/**
* Reference to main server object
*
* @var Sabre_DAV_Server
*/
private $server;
/**
* 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->xmlNamespaces[self::NS_OWNCLOUD] = 'oc';
$server->protectedProperties[] = '{' . self::NS_OWNCLOUD . '}id';
$this->server = $server;
$this->server->subscribeEvent('beforeGetProperties', array($this, 'beforeGetProperties'));
}
/**
* Adds all ownCloud-specific properties
*
* @param string $path
* @param Sabre_DAV_INode $node
* @param array $requestedProperties
* @param array $returnedProperties
* @return void
*/
public function beforeGetProperties($path, Sabre_DAV_INode $node, array &$requestedProperties, array &$returnedProperties) {
if ($node instanceof OC_Connector_Sabre_Node) {
$fileid_propertyname = '{' . self::NS_OWNCLOUD . '}id';
if (array_search($fileid_propertyname, $requestedProperties)) {
unset($requestedProperties[array_search($fileid_propertyname, $requestedProperties)]);
}
/** @var $node OC_Connector_Sabre_Node */
$fileId = $node->getFileId();
if (!is_null($fileId)) {
$returnedProperties[200][$fileid_propertyname] = $fileId;
}
}
}
}

View File

@ -45,6 +45,7 @@ abstract class OC_Connector_Sabre_Node implements Sabre_DAV_INode, Sabre_DAV_IPr
* @var string
*/
protected $path;
/**
* node fileinfo cache
* @var array
@ -211,6 +212,7 @@ abstract class OC_Connector_Sabre_Node implements Sabre_DAV_INode, Sabre_DAV_IPr
* properties should be returned
*/
public function getProperties($properties) {
if (is_null($this->property_cache)) {
$sql = 'SELECT * FROM `*PREFIX*properties` WHERE `userid` = ? AND `propertypath` = ?';
$result = OC_DB::executeAudited( $sql, array( OC_User::getUser(), $this->path ) );
@ -236,8 +238,11 @@ abstract class OC_Connector_Sabre_Node implements Sabre_DAV_INode, Sabre_DAV_IPr
$props = array();
foreach($properties as $property) {
if (isset($this->property_cache[$property])) $props[$property] = $this->property_cache[$property];
if (isset($this->property_cache[$property])) {
$props[$property] = $this->property_cache[$property];
}
}
return $props;
}
@ -260,4 +265,20 @@ abstract class OC_Connector_Sabre_Node implements Sabre_DAV_INode, Sabre_DAV_IPr
}
return $this->fileView;
}
/**
* @return mixed
*/
public function getFileId()
{
$this->getFileinfoCache();
if (isset($this->fileinfo_cache['fileid'])) {
$instanceId = OC_Util::getInstanceId();
$id = sprintf('%08d', $this->fileinfo_cache['fileid']);
return $instanceId . $id;
}
return null;
}
}

View File

@ -12,7 +12,7 @@ use Doctrine\DBAL\Configuration;
use Doctrine\DBAL\Cache\QueryCacheProfile;
use Doctrine\Common\EventManager;
class Connection extends \Doctrine\DBAL\Connection implements \OCP\IDBConnection {
class Connection extends \Doctrine\DBAL\Connection {
/**
* @var string $tablePrefix
*/

View File

@ -0,0 +1,99 @@
<?php
/**
* Copyright (c) 2013 Thomas Müller <deepdiver@owncloud.com>
* This file is licensed under the Affero General Public License version 3 or
* later.
* See the COPYING-README file.
*/
namespace OC\DB;
class ConnectionWrapper implements \OCP\IDBConnection {
private $connection;
public function __construct(Connection $conn) {
$this->connection = $conn;
}
/**
* Used to the owncloud database access away
* @param string $sql the sql query with ? placeholder for params
* @param int $limit the maximum number of rows
* @param int $offset from which row we want to start
* @return \Doctrine\DBAL\Driver\Statement The prepared statement.
*/
public function prepare($sql, $limit = null, $offset = null)
{
return $this->connection->prepare($sql, $limit, $offset);
}
/**
* Used to get the id of the just inserted element
* @param string $tableName the name of the table where we inserted the item
* @return int the id of the inserted element
*/
public function lastInsertId($table = null)
{
return $this->connection->lastInsertId($table);
}
/**
* Insert a row if a matching row doesn't exists.
* @param string The table name (will replace *PREFIX*) to perform the replace on.
* @param array
*
* The input array if in the form:
*
* array ( 'id' => array ( 'value' => 6,
* 'key' => true
* ),
* 'name' => array ('value' => 'Stoyan'),
* 'family' => array ('value' => 'Stefanov'),
* 'birth_date' => array ('value' => '1975-06-20')
* );
* @return bool
*
*/
public function insertIfNotExist($table, $input)
{
return $this->connection->insertIfNotExist($table, $input);
}
/**
* Start a transaction
* @return bool TRUE on success or FALSE on failure
*/
public function beginTransaction()
{
return $this->connection->beginTransaction();
}
/**
* Commit the database changes done during a transaction that is in progress
* @return bool TRUE on success or FALSE on failure
*/
public function commit()
{
return $this->connection->commit();
}
/**
* Rollback the database changes done during a transaction that is in progress
* @return bool TRUE on success or FALSE on failure
*/
public function rollBack()
{
return $this->connection->rollBack();
}
/**
* Gets the error code and message as a string for logging
* @return string
*/
public function getError()
{
return $this->connection->getError();
}
}

View File

@ -85,6 +85,16 @@ class OC_FileChunking {
}
}
/**
* Removes one specific chunk
* @param $index
*/
public function remove($index) {
$cache = $this->getCache();
$prefix = $this->getPrefix();
$cache->remove($prefix.$index);
}
public function signature_split($orgfile, $input) {
$info = unpack('n', fread($input, 2));
$blocksize = $info[1];

View File

@ -69,9 +69,15 @@ class Cache {
}
if (!isset(self::$mimetypeIds[$mime])) {
$result = \OC_DB::executeAudited('INSERT INTO `*PREFIX*mimetypes`(`mimetype`) VALUES(?)', array($mime));
self::$mimetypeIds[$mime] = \OC_DB::insertid('*PREFIX*mimetypes');
self::$mimetypes[self::$mimetypeIds[$mime]] = $mime;
try{
$result = \OC_DB::executeAudited('INSERT INTO `*PREFIX*mimetypes`(`mimetype`) VALUES(?)', array($mime));
self::$mimetypeIds[$mime] = \OC_DB::insertid('*PREFIX*mimetypes');
self::$mimetypes[self::$mimetypeIds[$mime]] = $mime;
}
catch (\Doctrine\DBAL\DBALException $e){
\OC_Log::write('core', 'Exception during mimetype insertion: ' . $e->getmessage(), \OC_Log::DEBUG);
return -1;
}
}
return self::$mimetypeIds[$mime];
@ -84,8 +90,8 @@ class Cache {
return isset(self::$mimetypes[$id]) ? self::$mimetypes[$id] : null;
}
protected function loadMimetypes(){
public function loadMimetypes(){
$result = \OC_DB::executeAudited('SELECT `id`, `mimetype` FROM `*PREFIX*mimetypes`', array());
if ($result) {
while ($row = $result->fetchRow()) {

View File

@ -190,24 +190,34 @@ class Scanner extends BasicEmitter {
}
$newChildren = array();
if ($this->storage->is_dir($path) && ($dh = $this->storage->opendir($path))) {
$exceptionOccurred = false;
\OC_DB::beginTransaction();
if (is_resource($dh)) {
while (($file = readdir($dh)) !== false) {
$child = ($path) ? $path . '/' . $file : $file;
if (!Filesystem::isIgnoredDir($file)) {
$newChildren[] = $file;
$data = $this->scanFile($child, $reuse, true);
if ($data) {
if ($data['size'] === -1) {
if ($recursive === self::SCAN_RECURSIVE) {
$childQueue[] = $child;
} else {
$size = -1;
try {
$data = $this->scanFile($child, $reuse, true);
if ($data) {
if ($data['size'] === -1) {
if ($recursive === self::SCAN_RECURSIVE) {
$childQueue[] = $child;
} else {
$size = -1;
}
} else if ($size !== -1) {
$size += $data['size'];
}
} else if ($size !== -1) {
$size += $data['size'];
}
}
catch (\Doctrine\DBAL\DBALException $ex){
// might happen if inserting duplicate while a scanning
// process is running in parallel
// log and ignore
\OC_Log::write('core', 'Exception while scanning file "' . $child . '": ' . $ex->getMessage(), \OC_Log::DEBUG);
$exceptionOccurred = true;
}
}
}
}
@ -217,6 +227,14 @@ class Scanner extends BasicEmitter {
$this->cache->remove($child);
}
\OC_DB::commit();
if ($exceptionOccurred){
// It might happen that the parallel scan process has already
// inserted mimetypes but those weren't available yet inside the transaction
// To make sure to have the updated mime types in such cases,
// we reload them here
$this->cache->loadMimetypes();
}
foreach ($childQueue as $child) {
$childSize = $this->scanChildren($child, self::SCAN_RECURSIVE, $reuse);
if ($childSize === -1) {

View File

@ -5,6 +5,7 @@ namespace OC;
use OC\AppFramework\Http\Request;
use OC\AppFramework\Utility\SimpleContainer;
use OC\Cache\UserCache;
use OC\DB\ConnectionWrapper;
use OC\Files\Node\Root;
use OC\Files\View;
use OCP\IServerContainer;
@ -289,7 +290,7 @@ class Server extends SimpleContainer implements IServerContainer {
* @return \OCP\IDBConnection
*/
function getDatabaseConnection() {
return \OC_DB::getConnection();
return new ConnectionWrapper(\OC_DB::getConnection());
}
/**

View File

@ -81,17 +81,35 @@ class URLGenerator implements IURLGenerator {
// Read the selected theme from the config file
$theme = \OC_Util::getTheme();
//if a theme has a png but not an svg always use the png
$basename = substr(basename($image),0,-4);
// Check if the app is in the app folder
if (file_exists(\OC::$SERVERROOT . "/themes/$theme/apps/$app/img/$image")) {
return \OC::$WEBROOT . "/themes/$theme/apps/$app/img/$image";
} elseif (!file_exists(\OC::$SERVERROOT . "/themes/$theme/apps/$app/img/$basename.svg")
&& file_exists(\OC::$SERVERROOT . "/themes/$theme/apps/$app/img/$basename.png")) {
return \OC::$WEBROOT . "/themes/$theme/apps/$app/img/$basename.png";
} elseif (file_exists(\OC_App::getAppPath($app) . "/img/$image")) {
return \OC_App::getAppWebPath($app) . "/img/$image";
} elseif (!file_exists(\OC_App::getAppPath($app) . "/img/$basename.svg")
&& file_exists(\OC_App::getAppPath($app) . "/img/$basename.png")) {
return \OC_App::getAppPath($app) . "/img/$basename.png";
} elseif (!empty($app) and file_exists(\OC::$SERVERROOT . "/themes/$theme/$app/img/$image")) {
return \OC::$WEBROOT . "/themes/$theme/$app/img/$image";
} elseif (!empty($app) and (!file_exists(\OC::$SERVERROOT . "/themes/$theme/$app/img/$basename.svg")
&& file_exists(\OC::$WEBROOT . "/themes/$theme/$app/img/$basename.png"))) {
return \OC::$WEBROOT . "/themes/$theme/$app/img/$basename.png";
} elseif (!empty($app) and file_exists(\OC::$SERVERROOT . "/$app/img/$image")) {
return \OC::$WEBROOT . "/$app/img/$image";
} elseif (!empty($app) and (!file_exists(\OC::$SERVERROOT . "/$app/img/$basename.svg")
&& file_exists(\OC::$WEBROOT . "/$app/img/$basename.png"))) {
return \OC::$WEBROOT . "/$app/img/$basename.png";
} elseif (file_exists(\OC::$SERVERROOT . "/themes/$theme/core/img/$image")) {
return \OC::$WEBROOT . "/themes/$theme/core/img/$image";
} elseif (!file_exists(\OC::$SERVERROOT . "/themes/$theme/core/img/$basename.svg")
&& file_exists(\OC::$SERVERROOT . "/themes/$theme/core/img/$basename.png")) {
return \OC::$WEBROOT . "/themes/$theme/core/img/$basename.png";
} elseif (file_exists(\OC::$SERVERROOT . "/core/img/$image")) {
return \OC::$WEBROOT . "/core/img/$image";
} else {

View File

@ -77,6 +77,39 @@ class Util {
\OC_LOG::write( $app, $message, $level );
}
/**
* @brief write exception into the log. Include the stack trace
* if DEBUG mode is enabled
* @param Exception $ex exception to log
*/
public static function logException( $app, \Exception $ex ) {
$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());
// first element is empty
array_shift($stack);
foreach ($stack as $s) {
\OCP\Util::writeLog($app, 'Exception: ' . $s, \OCP\Util::FATAL);
}
// include cause
$l = \OC_L10N::get('lib');
while (method_exists($ex, 'getPrevious') && $ex = $ex->getPrevious()) {
$message .= ' - '.$l->t('Caused by:').' ';
$message .= $ex->getMessage();
if ($ex->getCode()) {
$message .= '[' . $ex->getCode() . '] ';
}
\OCP\Util::writeLog($app, 'Exception: ' . $message, \OCP\Util::FATAL);
}
}
}
/**
* @brief get l10n object
* @param string $app

View File

@ -58,10 +58,6 @@ tr:hover>td.remove>a, tr:hover>td.password>img,tr:hover>td.displayName>img, tr:h
tr:hover>td.remove>a { float:right; }
li.selected { background-color:#ddd; }
table.grid { width:100%; }
#leftcontent, .leftcontent {
width: 256px;
}
#rightcontent, .rightcontent { top: 80px; left: 336px; }
#rightcontent { padding-left: 10px; }
div.quota {
float: right;

View File

@ -32,6 +32,6 @@ $(document).ready(function(){
});
$('#security').change(function(){
$.post(OC.filePath('settings','ajax','setsecurity.php'), { enforceHTTPS: $('#enforceHTTPSEnabled').val() },function(){} );
$.post(OC.filePath('settings','ajax','setsecurity.php'), { enforceHTTPS: $('#forcessl').val() },function(){} );
});
});

View File

@ -0,0 +1,34 @@
<?php
/**
* Copyright (c) 2013 Thomas Müller <thomas.mueller@tmit.eu>
* This file is licensed under the Affero General Public License version 3 or
* later.
* See the COPYING-README file.
*/
class Test_OC_Connector_Sabre_Directory extends PHPUnit_Framework_TestCase {
/**
* @expectedException Sabre_DAV_Exception_Forbidden
*/
public function testCreateSharedFileFails() {
$dir = new OC_Connector_Sabre_Directory('');
$dir->createFile('Shared');
}
/**
* @expectedException Sabre_DAV_Exception_Forbidden
*/
public function testCreateSharedFolderFails() {
$dir = new OC_Connector_Sabre_Directory('');
$dir->createDirectory('Shared');
}
/**
* @expectedException Sabre_DAV_Exception_Forbidden
*/
public function testDeleteSharedFolderFails() {
$dir = new OC_Connector_Sabre_Directory('Shared');
$dir->delete();
}
}

View File

@ -35,4 +35,11 @@ class Test_OC_Connector_Sabre_File extends PHPUnit_Framework_TestCase {
$etag = $file->put('test data');
}
/**
* @expectedException Sabre_DAV_Exception_Forbidden
*/
public function testDeleteSharedFails() {
$file = new OC_Connector_Sabre_File('Shared');
$file->delete();
}
}

View File

@ -1,10 +1,10 @@
<?php
// We only can count up. The 4. digit is only for the internal patchlevel to trigger DB upgrades between betas, final and RCs. This is _not_ the public version number. Reset minor/patchlevel when updating major/minor version number.
$OC_Version=array(5, 00, 0, 1);
$OC_Version=array(6, 00, 0, 2);
// The human radable string
$OC_VersionString='6.0 alpha 2';
$OC_VersionString='6.0 beta 1';
// The ownCloud edition
$OC_Edition='';