diff options
author | Georg Ehrke <dev@georgswebsite.de> | 2012-04-26 18:08:49 +0200 |
---|---|---|
committer | Georg Ehrke <dev@georgswebsite.de> | 2012-04-26 18:08:49 +0200 |
commit | 2b10371bdeb2c8a3d5cc2617ada5cf8195c264c9 (patch) | |
tree | f25b463c90992764887416c3082098fed6ecac65 /apps | |
parent | 40f95ffdf3edf9ab45c15bd5b9018d7f4d92baa9 (diff) | |
parent | 127796218314c6b1f19ba86f74caa913375aac8d (diff) | |
download | nextcloud-server-2b10371bdeb2c8a3d5cc2617ada5cf8195c264c9.tar.gz nextcloud-server-2b10371bdeb2c8a3d5cc2617ada5cf8195c264c9.zip |
fix merge conflicts
Diffstat (limited to 'apps')
43 files changed, 1141 insertions, 213 deletions
diff --git a/apps/calendar/ajax/event/edit.form.php b/apps/calendar/ajax/event/edit.form.php index ec50b78be6f..e963da32958 100644 --- a/apps/calendar/ajax/event/edit.form.php +++ b/apps/calendar/ajax/event/edit.form.php @@ -27,15 +27,15 @@ $vevent = $object->VEVENT; $dtstart = $vevent->DTSTART; $dtend = OC_Calendar_Object::getDTEndFromVEvent($vevent); switch($dtstart->getDateType()) { - case Sabre_VObject_Element_DateTime::LOCALTZ: - case Sabre_VObject_Element_DateTime::LOCAL: + case Sabre_VObject_Property_DateTime::LOCALTZ: + case Sabre_VObject_Property_DateTime::LOCAL: $startdate = $dtstart->getDateTime()->format('d-m-Y'); $starttime = $dtstart->getDateTime()->format('H:i'); $enddate = $dtend->getDateTime()->format('d-m-Y'); $endtime = $dtend->getDateTime()->format('H:i'); $allday = false; break; - case Sabre_VObject_Element_DateTime::DATE: + case Sabre_VObject_Property_DateTime::DATE: $startdate = $dtstart->getDateTime()->format('d-m-Y'); $starttime = ''; $dtend->getDateTime()->modify('-1 day'); diff --git a/apps/calendar/ajax/event/move.php b/apps/calendar/ajax/event/move.php index 0552c7bbc5b..75d174c13e1 100644 --- a/apps/calendar/ajax/event/move.php +++ b/apps/calendar/ajax/event/move.php @@ -27,19 +27,19 @@ $dtstart = $vevent->DTSTART; $dtend = OC_Calendar_Object::getDTEndFromVEvent($vevent); $start_type = $dtstart->getDateType(); $end_type = $dtend->getDateType(); -if ($allday && $start_type != Sabre_VObject_Element_DateTime::DATE){ - $start_type = $end_type = Sabre_VObject_Element_DateTime::DATE; +if ($allday && $start_type != Sabre_VObject_Property_DateTime::DATE){ + $start_type = $end_type = Sabre_VObject_Property_DateTime::DATE; $dtend->setDateTime($dtend->getDateTime()->modify('+1 day'), $end_type); } -if (!$allday && $start_type == Sabre_VObject_Element_DateTime::DATE){ - $start_type = $end_type = Sabre_VObject_Element_DateTime::LOCALTZ; +if (!$allday && $start_type == Sabre_VObject_Property_DateTime::DATE){ + $start_type = $end_type = Sabre_VObject_Property_DateTime::LOCALTZ; } $dtstart->setDateTime($dtstart->getDateTime()->add($delta), $start_type); $dtend->setDateTime($dtend->getDateTime()->add($delta), $end_type); unset($vevent->DURATION); -$vevent->setDateTime('LAST-MODIFIED', 'now', Sabre_VObject_Element_DateTime::UTC); -$vevent->setDateTime('DTSTAMP', 'now', Sabre_VObject_Element_DateTime::UTC); +$vevent->setDateTime('LAST-MODIFIED', 'now', Sabre_VObject_Property_DateTime::UTC); +$vevent->setDateTime('DTSTAMP', 'now', Sabre_VObject_Property_DateTime::UTC); $result = OC_Calendar_Object::edit($id, $vcalendar->serialize()); $lastmodified = $vevent->__get('LAST-MODIFIED')->getDateTime(); diff --git a/apps/calendar/ajax/event/resize.php b/apps/calendar/ajax/event/resize.php index 593835d86c5..260b6914426 100644 --- a/apps/calendar/ajax/event/resize.php +++ b/apps/calendar/ajax/event/resize.php @@ -30,8 +30,8 @@ $end_type = $dtend->getDateType(); $dtend->setDateTime($dtend->getDateTime()->add($delta), $end_type); unset($vevent->DURATION); -$vevent->setDateTime('LAST-MODIFIED', 'now', Sabre_VObject_Element_DateTime::UTC); -$vevent->setDateTime('DTSTAMP', 'now', Sabre_VObject_Element_DateTime::UTC); +$vevent->setDateTime('LAST-MODIFIED', 'now', Sabre_VObject_Property_DateTime::UTC); +$vevent->setDateTime('DTSTAMP', 'now', Sabre_VObject_Property_DateTime::UTC); OC_Calendar_Object::edit($id, $vcalendar->serialize()); $lastmodified = $vevent->__get('LAST-MODIFIED')->getDateTime(); diff --git a/apps/calendar/ajax/events.php b/apps/calendar/ajax/events.php index 3aa487fd231..8adaa4c98f3 100755 --- a/apps/calendar/ajax/events.php +++ b/apps/calendar/ajax/events.php @@ -20,7 +20,6 @@ $events = OC_Calendar_App::getrequestedEvents($_GET['calendar_id'], $start, $end $output = array(); foreach($events as $event){ $output[] = OC_Calendar_App::generateEventOutput($event, $start, $end); - } OC_JSON::encodedPrint($output); ?> diff --git a/apps/calendar/lib/object.php b/apps/calendar/lib/object.php index 825977c17c5..ae6fce3c842 100644 --- a/apps/calendar/lib/object.php +++ b/apps/calendar/lib/object.php @@ -590,7 +590,7 @@ class OC_Calendar_Object{ $vevent = new OC_VObject('VEVENT'); $vcalendar->add($vevent); - $vevent->setDateTime('CREATED', 'now', Sabre_VObject_Element_DateTime::UTC); + $vevent->setDateTime('CREATED', 'now', Sabre_VObject_Property_DateTime::UTC); $vevent->setUID(); return self::updateVCalendarFromRequest($request, $vcalendar); @@ -751,22 +751,22 @@ class OC_Calendar_Object{ } - $vevent->setDateTime('LAST-MODIFIED', 'now', Sabre_VObject_Element_DateTime::UTC); - $vevent->setDateTime('DTSTAMP', 'now', Sabre_VObject_Element_DateTime::UTC); + $vevent->setDateTime('LAST-MODIFIED', 'now', Sabre_VObject_Property_DateTime::UTC); + $vevent->setDateTime('DTSTAMP', 'now', Sabre_VObject_Property_DateTime::UTC); $vevent->setString('SUMMARY', $title); if($allday){ $start = new DateTime($from); $end = new DateTime($to.' +1 day'); - $vevent->setDateTime('DTSTART', $start, Sabre_VObject_Element_DateTime::DATE); - $vevent->setDateTime('DTEND', $end, Sabre_VObject_Element_DateTime::DATE); + $vevent->setDateTime('DTSTART', $start, Sabre_VObject_Property_DateTime::DATE); + $vevent->setDateTime('DTEND', $end, Sabre_VObject_Property_DateTime::DATE); }else{ $timezone = OC_Preferences::getValue(OC_USER::getUser(), 'calendar', 'timezone', date_default_timezone_get()); $timezone = new DateTimeZone($timezone); $start = new DateTime($from.' '.$fromtime, $timezone); $end = new DateTime($to.' '.$totime, $timezone); - $vevent->setDateTime('DTSTART', $start, Sabre_VObject_Element_DateTime::LOCALTZ); - $vevent->setDateTime('DTEND', $end, Sabre_VObject_Element_DateTime::LOCALTZ); + $vevent->setDateTime('DTSTART', $start, Sabre_VObject_Property_DateTime::LOCALTZ); + $vevent->setDateTime('DTEND', $end, Sabre_VObject_Property_DateTime::LOCALTZ); } unset($vevent->DURATION); diff --git a/apps/calendar/lib/search.php b/apps/calendar/lib/search.php index da5fa35bc21..0e1a9032666 100644 --- a/apps/calendar/lib/search.php +++ b/apps/calendar/lib/search.php @@ -26,7 +26,7 @@ class OC_Search_Provider_Calendar extends OC_Search_Provider{ $start_dt->setTimezone(new DateTimeZone($user_timezone)); $end_dt = $dtend->getDateTime(); $end_dt->setTimezone(new DateTimeZone($user_timezone)); - if ($dtstart->getDateType() == Sabre_VObject_Element_DateTime::DATE){ + if ($dtstart->getDateType() == Sabre_VObject_Property_DateTime::DATE){ $end_dt->modify('-1 sec'); if($start_dt->format('d.m.Y') != $end_dt->format('d.m.Y')){ $info = $l->t('Date') . ': ' . $start_dt->format('d.m.Y') . ' - ' . $end_dt->format('d.m.Y'); diff --git a/apps/contacts/ajax/uploadimport.php b/apps/contacts/ajax/uploadimport.php index ab680c8823f..f44335a961e 100644 --- a/apps/contacts/ajax/uploadimport.php +++ b/apps/contacts/ajax/uploadimport.php @@ -34,17 +34,52 @@ function debug($msg) { OC_Log::write('contacts','ajax/uploadimport.php: '.$msg, OC_Log::DEBUG); } +$view = OC_App::getStorage('contacts'); +$tmpfile = md5(rand()); + // If it is a Drag'n'Drop transfer it's handled here. $fn = (isset($_SERVER['HTTP_X_FILE_NAME']) ? $_SERVER['HTTP_X_FILE_NAME'] : false); if($fn) { - $view = OC_App::getStorage('contacts'); - $tmpfile = md5(rand()); if($view->file_put_contents('/'.$tmpfile, file_get_contents('php://input'))) { debug($fn.' uploaded'); OC_JSON::success(array('data' => array('path'=>'', 'file'=>$tmpfile))); + exit(); } else { bailOut(OC_Contacts_App::$l10n->t('Error uploading contacts to storage.')); } } +// File input transfers are handled here +if (!isset($_FILES['importfile'])) { + OC_Log::write('contacts','ajax/uploadphoto.php: No file was uploaded. Unknown error.', OC_Log::DEBUG); + OC_JSON::error(array('data' => array( 'message' => 'No file was uploaded. Unknown error' ))); + exit(); +} +$error = $_FILES['importfile']['error']; +if($error !== UPLOAD_ERR_OK) { + $errors = array( + 0=>OC_Contacts_App::$l10n->t("There is no error, the file uploaded with success"), + 1=>OC_Contacts_App::$l10n->t("The uploaded file exceeds the upload_max_filesize directive in php.ini").ini_get('upload_max_filesize'), + 2=>OC_Contacts_App::$l10n->t("The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form"), + 3=>OC_Contacts_App::$l10n->t("The uploaded file was only partially uploaded"), + 4=>OC_Contacts_App::$l10n->t("No file was uploaded"), + 6=>OC_Contacts_App::$l10n->t("Missing a temporary folder") + ); + bailOut($errors[$error]); +} +$file=$_FILES['importfile']; + +$tmpfname = tempnam("/tmp", "occOrig"); +if(file_exists($file['tmp_name'])) { + if($view->file_put_contents('/'.$tmpfile, file_get_contents($file['tmp_name']))) { + debug($fn.' uploaded'); + OC_JSON::success(array('data' => array('path'=>'', 'file'=>$tmpfile))); + } else { + bailOut(OC_Contacts_App::$l10n->t('Error uploading contacts to storage.')); + } +} else { + bailOut('Temporary file: \''.$file['tmp_name'].'\' has gone AWOL?'); +} + + ?> diff --git a/apps/contacts/css/contacts.css b/apps/contacts/css/contacts.css index 0bb9f975fc5..e3d2cfbdd66 100644 --- a/apps/contacts/css/contacts.css +++ b/apps/contacts/css/contacts.css @@ -100,4 +100,4 @@ input[type="checkbox"] { width: 20px; height: 20px; vertical-align: bottom; } .propertylist li > input[type="checkbox"],input[type="radio"] { float: left; clear: left; width: 20px; height: 20px; vertical-align: middle; } .propertylist li > select { float: left; max-width: 8em; } .typelist { float: left; max-width: 10em; } /* for multiselect */ -.addresslist { clear: both; }
\ No newline at end of file +.addresslist { clear: both; } diff --git a/apps/contacts/import.php b/apps/contacts/import.php index ca2c1e1605d..8e0a427399b 100644 --- a/apps/contacts/import.php +++ b/apps/contacts/import.php @@ -24,6 +24,11 @@ if(isset($_POST['fstype']) && $_POST['fstype'] == 'OC_FilesystemView') { } else { $file = OC_Filesystem::file_get_contents($_POST['path'] . '/' . $_POST['file']); } +if(!$file) { + OC_JSON::error(array('message' => 'Import file was empty.')); + exit(); +} +error_log('File: '.$file); if(isset($_POST['method']) && $_POST['method'] == 'new'){ $id = OC_Contacts_Addressbook::add(OC_User::getUser(), $_POST['addressbookname']); OC_Contacts_Addressbook::setActive($id, 1); diff --git a/apps/contacts/js/contacts.js b/apps/contacts/js/contacts.js index 18edb40a3cb..7e0fe8b41cf 100644 --- a/apps/contacts/js/contacts.js +++ b/apps/contacts/js/contacts.js @@ -1287,6 +1287,7 @@ Contacts={ }, Addressbooks:{ droptarget:undefined, + droptext:t('contacts', 'Drop a VCF file to import contacts.'), overview:function(){ if($('#chooseaddressbook_dialog').dialog('isOpen') == true){ $('#chooseaddressbook_dialog').dialog('moveToTop'); @@ -1345,8 +1346,16 @@ Contacts={ } }, loadImportHandlers:function() { + $('#import_upload_start').change(function(){ + Contacts.UI.Addressbooks.uploadImport(this.files); + }); + $('#importaddressbook_dialog').find('.upload').click(function() { + Contacts.UI.Addressbooks.droptarget.html(t('contacts', 'Uploading...')); + Contacts.UI.loading(Contacts.UI.Addressbooks.droptarget, true); + $('#import_upload_start').trigger('click'); + }); + $('#importaddressbook_dialog').find('.upload').tipsy(); this.droptarget = $('#import_drop_target'); - console.log($('#import_drop_target').html()); $(this.droptarget).bind('dragover',function(event){ $(event.target).addClass('droppable'); event.stopPropagation(); @@ -1371,13 +1380,13 @@ Contacts={ console.log('size: '+file.size+', type: '+file.type); if(file.size > $('#max_upload').val()){ OC.dialogs.alert(t('contacts','The file you are trying to upload exceed the maximum size for file uploads on this server.'), t('contacts','Upload too large')); - $(Contacts.UI.Addressbooks.droptarget).html(t('contacts', 'Drop a VCF file to import contacts.')); + $(Contacts.UI.Addressbooks.droptarget).html(Contacts.UI.Addressbooks.droptext); Contacts.UI.loading(Contacts.UI.Addressbooks.droptarget, false); return; } if(file.type.indexOf('text') != 0) { OC.dialogs.alert(t('contacts','You have dropped a file type that cannot be imported: ') + file.type, t('contacts','Wrong file type')); - $(Contacts.UI.Addressbooks.droptarget).html(t('contacts', 'Drop a VCF file to import contacts.')); + $(Contacts.UI.Addressbooks.droptarget).html(Contacts.UI.Addressbooks.droptext); Contacts.UI.loading(Contacts.UI.Addressbooks.droptarget, false); return; } @@ -1392,11 +1401,9 @@ Contacts={ response = $.parseJSON(xhr.responseText); if(response.status == 'success') { if(xhr.status == 200) { - $(Contacts.UI.Addressbooks.droptarget).html(t('contacts', 'Importing...')); - Contacts.UI.loading(Contacts.UI.Addressbooks.droptarget, true); Contacts.UI.Addressbooks.doImport(response.data.path, response.data.file); } else { - $(Contacts.UI.Addressbooks.droptarget).html(t('contacts', 'Drop a VCF file to import contacts.')); + $(Contacts.UI.Addressbooks.droptarget).html(Contacts.UI.Addressbooks.droptext); Contacts.UI.loading(Contacts.UI.Addressbooks.droptarget, false); OC.dialogs.alert(xhr.status + ': ' + xhr.responseText, t('contacts', 'Error')); } @@ -1405,7 +1412,7 @@ Contacts={ } } }; - xhr.open("POST", 'ajax/uploadimport.php?file='+encodeURIComponent(file.name), true); + xhr.open('POST', OC.filePath('contacts', 'ajax', 'uploadimport.php') + '?file='+encodeURIComponent(file.name), true); xhr.setRequestHeader('Cache-Control', 'no-cache'); xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest'); xhr.setRequestHeader('X_FILE_NAME', encodeURIComponent(file.name)); @@ -1414,12 +1421,39 @@ Contacts={ xhr.send(file); } }, + uploadImport:function(filelist) { + if(!filelist) { + OC.dialogs.alert(t('contacts','No files selected for upload.'), t('contacts', 'Error')); + return; + } + //var file = filelist.item(0); + var file = filelist[0]; + var target = $('#import_upload_target'); + var form = $('#import_upload_form'); + var totalSize=0; + if(file.size > $('#max_upload').val()){ + OC.dialogs.alert(t('contacts','The file you are trying to upload exceed the maximum size for file uploads on this server.'), t('contacts', 'Error')); + return; + } else { + target.load(function(){ + var response=jQuery.parseJSON(target.contents().text()); + if(response != undefined && response.status == 'success'){ + Contacts.UI.Addressbooks.doImport(response.data.path, response.data.file); + }else{ + OC.dialogs.alert(response.data.message, t('contacts', 'Error')); + } + }); + form.submit(); + } + }, importAddressbook:function(object){ var tr = $(document.createElement('tr')) .load(OC.filePath('contacts', 'ajax', 'importaddressbook.php')); $(object).closest('tr').after(tr).hide(); }, doImport:function(path, file){ + $(Contacts.UI.Addressbooks.droptarget).html(t('contacts', 'Importing...')); + Contacts.UI.loading(Contacts.UI.Addressbooks.droptarget, true); var id = $('#importaddressbook_dialog').find('#book').val(); console.log('Selected book: ' + id); $.post(OC.filePath('contacts', '', 'import.php'), { id: id, path: path, file: file, fstype: 'OC_FilesystemView' }, @@ -1428,6 +1462,10 @@ Contacts={ Contacts.UI.Addressbooks.droptarget.html(t('contacts', 'Import done. Success/Failure: ')+jsondata.data.imported+'/'+jsondata.data.failed); $('#chooseaddressbook_dialog').find('#close_button').val(t('contacts', 'OK')); Contacts.UI.Contacts.update(); + setTimeout( + function() { + $(Contacts.UI.Addressbooks.droptarget).html(Contacts.UI.Addressbooks.droptext); + }, 5000); } else { OC.dialogs.alert(jsondata.data.message, t('contacts', 'Error')); } @@ -1590,7 +1628,7 @@ $(document).ready(function(){ * Profile picture upload handling */ // New profile picture selected - $('#file_upload_start').live('change',function(){ + $('#file_upload_start').change(function(){ Contacts.UI.Card.uploadPhoto(this.files); }); $('#contacts_details_photo_wrapper').bind('dragover',function(event){ @@ -1662,7 +1700,7 @@ $(document).ready(function(){ }; // Start loading indicator. //$('#contacts_details_photo_progress').show()(); - xhr.open("POST", OC.filePath('contacts', 'ajax', 'uploadphoto.php')+'?id='+Contacts.UI.Card.id+'&imagefile='+encodeURIComponent(file.name), true); + xhr.open('POST', OC.filePath('contacts', 'ajax', 'uploadphoto.php')+'?id='+Contacts.UI.Card.id+'&imagefile='+encodeURIComponent(file.name), true); xhr.setRequestHeader('Cache-Control', 'no-cache'); xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest'); xhr.setRequestHeader('X_FILE_NAME', encodeURIComponent(file.name)); @@ -1691,4 +1729,4 @@ $(document).ready(function(){ Contacts.UI.Card.addProperty(type); $('#contacts_propertymenu').hide(); }); -});
\ No newline at end of file +}); diff --git a/apps/contacts/templates/part.contact.php b/apps/contacts/templates/part.contact.php index dec081a9b89..64a024c0926 100644 --- a/apps/contacts/templates/part.contact.php +++ b/apps/contacts/templates/part.contact.php @@ -24,7 +24,6 @@ $id = isset($_['id']) ? $_['id'] : ''; <div id="contact_photo" class="contactsection"> <form class="float" id="file_upload_form" action="ajax/uploadphoto.php" method="post" enctype="multipart/form-data" target="file_upload_target"> - <fieldset id="photo"> <div class="tip propertycontainer" id="contacts_details_photo_wrapper" title="<?php echo $l->t('Click or drop to upload picture'); ?> (max <?php echo $_['uploadMaxHumanFilesize']; ?>)" data-element="PHOTO"> <!-- img style="padding: 1em;" id="contacts_details_photo" alt="Profile picture" src="photo.php?id=<?php echo $_['id']; ?>" / --> <progress id="contacts_details_photo_progress" style="display:none;" value="0" max="100">0 %</progress> @@ -34,7 +33,6 @@ $id = isset($_['id']) ? $_['id'] : ''; <input type="hidden" class="max_human_file_size" value="(max <?php echo $_['uploadMaxHumanFilesize']; ?>)"> <input id="file_upload_start" type="file" accept="image/*" name="imagefile" /> <iframe name="file_upload_target" id='file_upload_target' src=""></iframe> - </fieldset> </form> </div> <!-- contact_photo --> diff --git a/apps/files/ajax/scan.php b/apps/files/ajax/scan.php index 488f68e6b3c..a227dcc3ffc 100644 --- a/apps/files/ajax/scan.php +++ b/apps/files/ajax/scan.php @@ -3,6 +3,7 @@ set_time_limit(0);//scanning can take ages $force=isset($_GET['force']) and $_GET['force']=='true'; +$dir=isset($_GET['dir'])?$_GET['dir']:''; $checkOnly=isset($_GET['checkonly']) and $_GET['checkonly']=='true'; if(!$checkOnly){ @@ -14,7 +15,7 @@ if(!$checkOnly){ if($force or !OC_FileCache::inCache('')){ if(!$checkOnly){ OC_DB::beginTransaction(); - OC_FileCache::scan('',$eventSource); + OC_FileCache::scan($dir,$eventSource); OC_FileCache::clean(); OC_DB::commit(); $eventSource->send('success',true); diff --git a/apps/files/css/files.css b/apps/files/css/files.css index 99623b6355e..a135f7ded5b 100644 --- a/apps/files/css/files.css +++ b/apps/files/css/files.css @@ -30,6 +30,8 @@ .file_upload_filename { position: relative; z-index:100; padding-left: 0.8em; padding-right: 0.8em; cursor:pointer; border-top-left-radius:0; border-bottom-left-radius:0; } .file_upload_filename img { position: absolute; top: 0.4em; left: 0.4em; -ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=100)"; filter:alpha(opacity=100); opacity:1; } +#upload { position:absolute; right:13.5em; top:0em; } +#upload #uploadprogressbar { position:relative; display:inline-block; width:10em; height:1.5em; top:.4em; } .file_upload_form, .file_upload_wrapper, .file_upload_start, .file_upload_filename, #file_upload_submit { cursor:pointer; } @@ -41,7 +43,7 @@ tbody tr { background-color:#fff; height:2.5em; } tbody tr:hover, tbody tr:active, tbody tr.selected { background-color:#f8f8f8; } tbody tr.selected { background-color:#eee; } tbody a { color:#000; } -span.extension, td.date { color:#999; } +span.extension, span.uploading, td.date { color:#999; } span.extension { text-transform:lowercase; -ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=70)"; filter:alpha(opacity=70); opacity:.7; -webkit-transition:opacity 300ms; -moz-transition:opacity 300ms; -o-transition:opacity 300ms; transition:opacity 300ms; } tr:hover span.extension { -ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=100)"; filter:alpha(opacity=100); opacity:1; color:#777; } div.crumb { float:left; display:block; background:no-repeat right 0; padding:.75em 1.5em 0 1em; height:2.9em; } @@ -60,8 +62,10 @@ table td.filename a.name { display:block; height:1.5em; vertical-align:middle; m table tr[data-type="dir"] td.filename a.name span.nametext {font-weight:bold; } table td.filename a.name input, table td.filename a.name form { width:100%; cursor:text; } table td.filename a, table td.login, table td.logout, table td.download, table td.upload, table td.create, table td.delete { padding:.2em .5em .5em 0; } -table td.filename .nametext, .modified { float:left; padding:.3em 0; } +table td.filename .nametext, .uploadtext, .modified { float:left; padding:.3em 0; } +// TODO fix usability bug (accidental file/folder selection) table td.filename .nametext { width:70%; overflow:hidden; } +table td.filename .uploadtext { font-weight:normal; margin-left:.5em; } table td.filename form { float:left; font-size:.85em; } table thead.fixed tr{ position:fixed; top:6.5em; z-index:49; -moz-box-shadow:0 -3px 7px #ddd; -webkit-box-shadow:0 -3px 7px #ddd; box-shadow:0 -3px 7px #ddd; } table thead.fixed { height:2em; } diff --git a/apps/files/index.php b/apps/files/index.php index 46b511d66eb..8464db30f01 100644 --- a/apps/files/index.php +++ b/apps/files/index.php @@ -26,6 +26,8 @@ OC_Util::checkLoggedIn(); // Load the files we need OC_Util::addStyle( "files", "files" ); +OC_Util::addScript( "files", "jquery.iframe-transport" ); +OC_Util::addScript( "files", "jquery.fileupload" ); OC_Util::addScript( "files", "files" ); OC_Util::addScript( 'files', 'filelist' ); OC_Util::addScript( 'files', 'fileactions' ); diff --git a/apps/files/js/fileactions.js b/apps/files/js/fileactions.js index 481802e0d63..68268a7d3a9 100644 --- a/apps/files/js/fileactions.js +++ b/apps/files/js/fileactions.js @@ -140,7 +140,20 @@ $(document).ready(function(){ }); FileActions.register('all','Delete',function(){return OC.imagePath('core','actions/delete')},function(filename){ - FileList.do_delete(filename); + if(Files.cancelUpload(filename)) { + if(filename.substr){ + filename=[filename]; + } + $.each(filename,function(index,file){ + var filename = $('tr').filterAttr('data-file',file); + filename.hide(); + filename.find('input[type="checkbox"]').removeAttr('checked'); + filename.removeClass('selected'); + }); + procesSelection(); + }else{ + FileList.do_delete(filename); + } }); FileActions.register('all','Rename',function(){return OC.imagePath('core','actions/rename')},function(filename){ diff --git a/apps/files/js/filelist.js b/apps/files/js/filelist.js index 5bd85fc29ef..febdfc473b1 100644 --- a/apps/files/js/filelist.js +++ b/apps/files/js/filelist.js @@ -43,6 +43,7 @@ FileList={ td.append('<input type="checkbox" />'); var link_elem = $('<a></a>').attr({ "class": "name", "href": "index.php?dir="+ encodeURIComponent($('#dir').val()+'/'+name).replace(/%2F/g, '/') }); link_elem.append($('<span></span>').addClass('nametext').text(name)); + link_elem.append($('<span></span>').attr({'class': 'uploadtext', 'currentUploads': 0})); td.append(link_elem); html.append(td); if(size!='Pending'){ diff --git a/apps/files/js/files.js b/apps/files/js/files.js index 9d83e5e6d26..2dce00035e1 100644 --- a/apps/files/js/files.js +++ b/apps/files/js/files.js @@ -1,3 +1,32 @@ +var uploadingFiles = {}; +Files={ + cancelUpload:function(filename) { + if(uploadingFiles[filename]) { + uploadingFiles[filename].abort(); + delete uploadingFiles[filename]; + return true; + } + return false; + }, + cancelUploads:function() { + $.each(uploadingFiles,function(index,file) { + if(typeof file['abort'] === 'function') { + file.abort(); + var filename = $('tr').filterAttr('data-file',index); + filename.hide(); + filename.find('input[type="checkbox"]').removeAttr('checked'); + filename.removeClass('selected'); + } else { + $.each(file,function(i,f) { + f.abort(); + delete file[i]; + }); + } + delete uploadingFiles[index]; + }); + procesSelection(); + } +} $(document).ready(function() { $('#fileList tr').each(function(){ //little hack to set unescape filenames in attribute @@ -151,83 +180,205 @@ $(document).ready(function() { return false; }); - $('.file_upload_start').live('change',function(){ - var form=$(this).closest('form'); - var that=this; - var uploadId=form.attr('data-upload-id'); - var files=this.files; - var target=form.children('iframe'); - var totalSize=0; - if(files){ - for(var i=0;i<files.length;i++){ - totalSize+=files[i].size; - if(FileList.deleteFiles && FileList.deleteFiles.indexOf(files[i].name)!=-1){//finish delete if we are uploading a deleted file - FileList.finishDelete(function(){ - $(that).change(); - }); - return; - } - } - } - if(totalSize>$('#max_upload').val()){ - $( "#uploadsize-message" ).dialog({ - modal: true, - buttons: { - Close: function() { - $( this ).dialog( "close" ); + // drag&drop support using jquery.fileupload + // TODO use OC.dialogs + $(document).bind('drop dragover', function (e) { + e.preventDefault(); // prevent browser from doing anything, if file isn't dropped in dropZone + }); + + $(function() { + $('.file_upload_start').fileupload({ + dropZone: $('#content'), // restrict dropZone to content div + add: function(e, data) { + var files = data.files; + var totalSize=0; + if(files){ + for(var i=0;i<files.length;i++){ + totalSize+=files[i].size; + if(FileList.deleteFiles && FileList.deleteFiles.indexOf(files[i].name)!=-1){//finish delete if we are uploading a deleted file + FileList.finishDelete(function(){ + $('.file_upload_start').change(); + }); + return; + } } } - }); - }else{ - target.load(function(){ - var response=jQuery.parseJSON(target.contents().find('body').text()); - //set mimetype and if needed filesize - if(response){ - if(response[0] != undefined && response[0].status == 'success'){ - for(var i=0;i<response.length;i++){ - var file=response[i]; + if(totalSize>$('#max_upload').val()){ + $( '#uploadsize-message' ).dialog({ + modal: true, + buttons: { + Close: function() { + $( this ).dialog( 'close' ); + } + } + }); + }else{ + if($.support.xhrFileUpload) { + for(var i=0;i<files.length;i++){ + var fileName = files[i].name + var dropTarget = $(e.originalEvent.target).closest('tr'); + if(dropTarget && dropTarget.attr('data-type') === 'dir') { // drag&drop upload to folder + var dirName = dropTarget.attr('data-file') + var jqXHR = $('.file_upload_start').fileupload('send', {files: files[i], + formData: function(form) { + var formArray = form.serializeArray(); + formArray[1]['value'] = dirName; + return formArray; + }}).success(function(result, textStatus, jqXHR) { + var response; + response=jQuery.parseJSON(result); + if(response[0] == undefined || response[0].status != 'success') { + $('#notification').text(t('files', response.data.message)); + $('#notification').fadeIn(); + } + var file=response[0]; + delete uploadingFiles[dirName][file.name]; + var currentUploads = parseInt(uploadtext.attr('currentUploads')); + currentUploads -= 1; + uploadtext.attr('currentUploads', currentUploads); + if(currentUploads === 0) { + var img = OC.imagePath('core', 'filetypes/folder.png'); + var tr=$('tr').filterAttr('data-file',dirName); + tr.find('td.filename').attr('style','background-image:url('+img+')'); + uploadtext.text(''); + uploadtext.hide(); + } else { + uploadtext.text(currentUploads + ' files uploading') + } + }) + .error(function(jqXHR, textStatus, errorThrown) { + if(errorThrown === 'abort') { + var currentUploads = parseInt(uploadtext.attr('currentUploads')); + currentUploads -= 1; + uploadtext.attr('currentUploads', currentUploads); + if(currentUploads === 0) { + var img = OC.imagePath('core', 'filetypes/folder.png'); + var tr=$('tr').filterAttr('data-file',dirName); + tr.find('td.filename').attr('style','background-image:url('+img+')'); + uploadtext.text(''); + uploadtext.hide(); + } else { + uploadtext.text(currentUploads + ' files uploading') + } + $('#notification').hide(); + $('#notification').text(t('files', 'Upload cancelled.')); + $('#notification').fadeIn(); + } + }); + //TODO test with filenames containing slashes + if(uploadingFiles[dirName] === undefined) { + uploadingFiles[dirName] = {}; + } + uploadingFiles[dirName][fileName] = jqXHR; + } else { + var jqXHR = $('.file_upload_start').fileupload('send', {files: files[i]}) + .success(function(result, textStatus, jqXHR) { + var response; + response=jQuery.parseJSON(result); + if(response[0] != undefined && response[0].status == 'success') { + var file=response[0]; + delete uploadingFiles[file.name]; + $('tr').filterAttr('data-file',file.name).data('mime',file.mime); + var size = $('tr').filterAttr('data-file',file.name).find('td.filesize').text(); + if(size==t('files','Pending')){ + $('tr').filterAttr('data-file',file.name).find('td.filesize').text(file.size); + } + FileList.loadingDone(file.name); + } else { + $('#notification').text(t('files', response.data.message)); + $('#notification').fadeIn(); + $('#fileList > tr').not('[data-mime]').fadeOut(); + $('#fileList > tr').not('[data-mime]').remove(); + } + }) + .error(function(jqXHR, textStatus, errorThrown) { + if(errorThrown === 'abort') { + $('#notification').hide(); + $('#notification').text(t('files', 'Upload cancelled.')); + $('#notification').fadeIn(); + } + }); + uploadingFiles[files[i].name] = jqXHR; + } + } + }else{ + data.submit().success(function(data, status) { + response = jQuery.parseJSON(data[0].body.innerText); + if(response[0] != undefined && response[0].status == 'success') { + var file=response[0]; + delete uploadingFiles[file.name]; $('tr').filterAttr('data-file',file.name).data('mime',file.mime); - if(size=='Pending'){ + var size = $('tr').filterAttr('data-file',file.name).find('td.filesize').text(); + if(size==t('files','Pending')){ $('tr').filterAttr('data-file',file.name).find('td.filesize').text(file.size); } FileList.loadingDone(file.name); + } else { + $('#notification').text(t('files', response.data.message)); + $('#notification').fadeIn(); + $('#fileList > tr').not('[data-mime]').fadeOut(); + $('#fileList > tr').not('[data-mime]').remove(); } - } - else{ - $('#notification').text(t('files',response.data.message)); - $('#notification').fadeIn(); - $('#fileList > tr').not('[data-mime]').fadeOut(); - $('#fileList > tr').not('[data-mime]').remove(); - } + }); } - }); - form.submit(); - var date=new Date(); - if(files){ - for(var i=0;i<files.length;i++){ - if(files[i].size>0){ - var size=files[i].size; - }else{ - var size=t('files','Pending'); - } + + var date=new Date(); if(files){ + for(var i=0;i<files.length;i++){ + if(files[i].size>0){ + var size=files[i].size; + }else{ + var size=t('files','Pending'); + } + if(files && !dirName){ FileList.addFile(getUniqueName(files[i].name),size,date,true); + } else if(dirName) { + var uploadtext = $('tr').filterAttr('data-type', 'dir').filterAttr('data-file', dirName).find('.uploadtext') + var currentUploads = parseInt(uploadtext.attr('currentUploads')); + currentUploads += 1; + uploadtext.attr('currentUploads', currentUploads); + if(currentUploads === 1) { + var img = OC.imagePath('core', 'loading.gif'); + var tr=$('tr').filterAttr('data-file',dirName); + tr.find('td.filename').attr('style','background-image:url('+img+')'); + uploadtext.text('1 file uploading'); + uploadtext.show(); + } else { + uploadtext.text(currentUploads + ' files uploading') + } + } + } + }else{ + var filename=this.value.split('\\').pop(); //ie prepends C:\fakepath\ in front of the filename + FileList.addFile(getUniqueName(filename),'Pending',date,true); } } - }else{ - var filename=this.value.split('\\').pop(); //ie prepends C:\fakepath\ in front of the filename - FileList.addFile(getUniqueName(filename),'Pending',date,true); + }, + fail: function(e, data) { + // TODO: cancel upload & display error notification + }, + progress: function(e, data) { + // TODO: show nice progress bar in file row + }, + progressall: function(e, data) { + var progress = (data.loaded/data.total)*100; + $('#uploadprogressbar').progressbar('value',progress); + }, + start: function(e, data) { + $('#uploadprogressbar').progressbar({value:0}); + $('#uploadprogressbar').fadeIn(); + if(data.dataType != 'iframe ') { + $('#upload input.stop').show(); + } + }, + stop: function(e, data) { + if(data.dataType != 'iframe ') { + $('#upload input.stop').hide(); + } + $('#uploadprogressbar').progressbar('value',100); + $('#uploadprogressbar').fadeOut(); } - - //clone the upload form and hide the new one to allow users to start a new upload while the old one is still uploading - var clone=form.clone(); - uploadId++; - clone.attr('data-upload-id',uploadId); - clone.attr('target','file_upload_target_'+uploadId); - clone.children('iframe').attr('name','file_upload_target_'+uploadId) - clone.insertBefore(form); - form.hide(); - } + }) }); //add multiply file upload attribute to all browsers except konqueror (which crashes when it's used) @@ -370,12 +521,15 @@ $(document).ready(function() { }, "json"); }); -function scanFiles(force){ +function scanFiles(force,dir){ + if(!dir){ + dir=''; + } force=!!force; //cast to bool scanFiles.scanning=true; $('#scanning-message').show(); $('#fileList').remove(); - var scannerEventSource=new OC.EventSource(OC.filePath('files','ajax','scan.php'),{force:force}); + var scannerEventSource=new OC.EventSource(OC.filePath('files','ajax','scan.php'),{force:force,dir:dir}); scanFiles.cancel=scannerEventSource.close.bind(scannerEventSource); scannerEventSource.listen('scanning',function(data){ $('#scan-count').text(data.count+' files scanned'); diff --git a/apps/files/templates/index.php b/apps/files/templates/index.php index 3571950467e..fc385e1ed3a 100644 --- a/apps/files/templates/index.php +++ b/apps/files/templates/index.php @@ -22,6 +22,11 @@ <iframe name="file_upload_target_1" class='file_upload_target' src=""></iframe> </form> </div> + <div id="upload"> + <div id="uploadprogressbar"></div> + <input type="button" class="stop" style="display:none" value="<?php echo $l->t('Cancel upload');?>" onclick="javascript:Files.cancelUploads();" /> + </div> + </div> <div id="file_action_panel"></div> <?php else:?> diff --git a/apps/files/templates/part.list.php b/apps/files/templates/part.list.php index 5a5941fc7ae..b2db4cbb8df 100644 --- a/apps/files/templates/part.list.php +++ b/apps/files/templates/part.list.php @@ -21,6 +21,10 @@ <?php echo htmlspecialchars($file['basename']);?><span class='extension'><?php echo $file['extension'];?></span> <?php endif;?> </span> + <?php if($file['type'] == 'dir'):?> + <span class="uploadtext" currentUploads="0"> + </span> + <?php endif;?> </a> </td> <td class="filesize" title="<?php echo human_file_size($file['size']); ?>" style="color:rgb(<?php echo $simple_size_color.','.$simple_size_color.','.$simple_size_color ?>)"><?php echo $simple_file_size; ?></td> diff --git a/apps/files_encryption/lib/cryptstream.php b/apps/files_encryption/lib/cryptstream.php index 21fa38e4b59..07a2e523a42 100644 --- a/apps/files_encryption/lib/cryptstream.php +++ b/apps/files_encryption/lib/cryptstream.php @@ -33,6 +33,7 @@ class OC_CryptStream{ private $path; private $readBuffer;//for streams that dont support seeking private $meta=array();//header/meta for source stream + private $count; public function stream_open($path, $mode, $options, &$opened_path){ $path=str_replace('crypt://','',$path); @@ -92,16 +93,6 @@ class OC_CryptStream{ $data=substr($block,0,$currentPos%8192).$data; } while(strlen($data)>0){ - if(strlen($data)<8192){ - //fetch the current data in that block and append it to the input so we always write entire blocks - $oldPos=ftell($this->source); - $encryptedBlock=fread($this->source,8192); - fseek($this->source,$oldPos); - if($encryptedBlock){ - $block=OC_Crypt::decrypt($encryptedBlock); - $data.=substr($block,strlen($data)); - } - } $encrypted=OC_Crypt::encrypt(substr($data,0,8192)); fwrite($this->source,$encrypted); $data=substr($data,8192); @@ -139,7 +130,9 @@ class OC_CryptStream{ } public function stream_close(){ - OC_FileCache::put($this->path,array('encrypted'=>true)); + if($this->meta['mode']!='r' and $this->meta['mode']!='rb'){ + OC_FileCache::put($this->path,array('encrypted'=>true)); + } return fclose($this->source); } }
\ No newline at end of file diff --git a/apps/files_encryption/lib/proxy.php b/apps/files_encryption/lib/proxy.php index e3a106d0d04..d65bcba8bfa 100644 --- a/apps/files_encryption/lib/proxy.php +++ b/apps/files_encryption/lib/proxy.php @@ -27,7 +27,6 @@ class OC_FileProxy_Encryption extends OC_FileProxy{ private static $blackList=null; //mimetypes blacklisted from encryption - private static $metaData=array(); //metadata cache private static $enableEncryption=null; /** @@ -60,13 +59,8 @@ class OC_FileProxy_Encryption extends OC_FileProxy{ * @return bool */ private static function isEncrypted($path){ - if(isset(self::$metaData[$path])){ - $metadata=self::$metaData[$path]; - }else{ - $metadata=OC_FileCache::getCached($path); - self::$metaData[$path]=$metadata; - } - return (bool)$metadata['encrypted']; + $metadata=OC_FileCache::getCached($path); + return isset($metadata['encrypted']) and (bool)$metadata['encrypted']; } public function preFile_put_contents($path,&$data){ @@ -98,12 +92,7 @@ class OC_FileProxy_Encryption extends OC_FileProxy{ //first encrypt the target file so we don't end up with a half encrypted file OC_Log::write('files_encryption','Decrypting '.$path.' before writing',OC_Log::DEBUG); $tmp=fopen('php://temp'); - while(!feof($result)){ - $chunk=fread($result,8192); - if($chunk){ - fwrite($tmp,$chunk); - } - } + OC_Helper::streamCopy($result,$tmp); fclose($result); OC_Filesystem::file_put_contents($path,$tmp); fclose($tmp); diff --git a/apps/files_external/lib/swift.php b/apps/files_external/lib/swift.php index e53eb1ff3b6..a987d17d799 100644 --- a/apps/files_external/lib/swift.php +++ b/apps/files_external/lib/swift.php @@ -28,6 +28,8 @@ class OC_FileStorage_SWIFT extends OC_Filestorage_Common{ private $rootContainer; private static $tempFiles=array(); + private $objects=array(); + private $containers=array(); const SUBCONTAINER_FILE='.subcontainers'; @@ -38,7 +40,7 @@ class OC_FileStorage_SWIFT extends OC_Filestorage_Common{ */ private function getContainerName($path){ $path=trim($this->root.$path,'/'); - return md5($path); + return str_replace('/','\\',$path); } /** @@ -50,8 +52,12 @@ class OC_FileStorage_SWIFT extends OC_Filestorage_Common{ if($path=='' or $path=='/'){ return $this->rootContainer; } + if(isset($this->containers[$path])){ + return $this->containers[$path]; + } try{ $container=$this->conn->get_container($this->getContainerName($path)); + $this->containers[$path]=$container; return $container; }catch(NoSuchContainerException $e){ return null; @@ -87,12 +93,16 @@ class OC_FileStorage_SWIFT extends OC_Filestorage_Common{ * @return CF_Object */ private function getObject($path){ + if(isset($this->objects[$path])){ + return $this->objects[$path]; + } $container=$this->getContainer(dirname($path)); if(is_null($container)){ return null; }else{ try{ $obj=$container->get_object(basename($path)); + $this->objects[$path]=$obj; return $obj; }catch(NoSuchObjectException $e){ return null; @@ -295,6 +305,7 @@ class OC_FileStorage_SWIFT extends OC_Filestorage_Common{ } $this->conn->delete_container($this->getContainerName($path)); + unset($this->containers[$path]); return true; } } @@ -309,12 +320,14 @@ class OC_FileStorage_SWIFT extends OC_Filestorage_Common{ if($sub){ $this->emptyContainer($path.'/'.$sub); $this->conn->delete_container($this->getContainerName($path.'/'.$sub)); + unset($this->containers[$path.'/'.$sub]); } } $objects=$this->getObjects($container); foreach($objects as $object){ $container->delete_object($object); + unset($this->objects[$path.'/'.$object]); } } @@ -381,6 +394,7 @@ class OC_FileStorage_SWIFT extends OC_Filestorage_Common{ if($this->objectExists($path)){ $container=$this->getContainer(dirname($path)); $container->delete_object(basename($path)); + unset($this->objects[$path]); }else{ return false; } @@ -447,6 +461,7 @@ class OC_FileStorage_SWIFT extends OC_Filestorage_Common{ $sourceContainer=$this->getContainer(dirname($path1)); $targetContainer=$this->getContainer(dirname($path2)); $result=$sourceContainer->move_object_to(basename($path1),$targetContainer,basename($path2)); + unset($this->objects[$path1]); if($result){ $targetObj=$this->getObject($path2); $this->resetMTime($targetObj); diff --git a/apps/files_sharing/ajax/email.php b/apps/files_sharing/ajax/email.php new file mode 100644 index 00000000000..d6d53c49bff --- /dev/null +++ b/apps/files_sharing/ajax/email.php @@ -0,0 +1,15 @@ +<?php + +require_once('../../../lib/base.php'); + +OC_JSON::checkLoggedIn(); +OC_JSON::checkAppEnabled('files_sharing'); +$user = OC_User::getUser(); +// TODO translations +$subject = $user + ' ' + 'shared a file with you'; +$link = $_POST['link'] + '&f=' + $_POST['f']; +$text = $user + ' ' + 'shared the file' + ' ' + $_POST['f'] + ' ' + 'with you.' + ' ' + 'It is available for download here:' + ' ' + $link; +$fromaddress = OC_Preferences::getValue($user, 'settings', 'email', 'owncloud.org'); +OC_Mail::send($_POST['toaddress'], $_POST['toaddress'], $subject, $text, $fromaddress, $user); + +?>
\ No newline at end of file diff --git a/apps/files_sharing/ajax/toggleresharing.php b/apps/files_sharing/ajax/toggleresharing.php new file mode 100644 index 00000000000..72af1eedec1 --- /dev/null +++ b/apps/files_sharing/ajax/toggleresharing.php @@ -0,0 +1,13 @@ +<?php + +require_once('../../../lib/base.php'); + +OC_JSON::checkAppEnabled('files_sharing'); +OC_JSON::checkAdminUser(); +if ($_POST['resharing'] == true) { + OC_Appconfig::setValue('files_sharing', 'resharing', 'yes'); +} else { + OC_Appconfig::setValue('files_sharing', 'resharing', 'no'); +} + +?> diff --git a/apps/files_sharing/appinfo/app.php b/apps/files_sharing/appinfo/app.php index 8049e9b0ae3..645f4f5e4f2 100644 --- a/apps/files_sharing/appinfo/app.php +++ b/apps/files_sharing/appinfo/app.php @@ -3,10 +3,17 @@ require_once('apps/files_sharing/sharedstorage.php'); OC::$CLASSPATH['OC_Share'] = "apps/files_sharing/lib_share.php"; +OC_APP::registerAdmin('files_sharing', 'settings'); OC_Hook::connect("OC_Filesystem", "post_delete", "OC_Share", "deleteItem"); OC_Hook::connect("OC_Filesystem", "post_rename", "OC_Share", "renameItem"); OC_Hook::connect("OC_Filesystem", "post_write", "OC_Share", "updateItem"); -OC_Util::addScript("files_sharing", "share"); +OC_Hook::connect('OC_User', 'post_deleteUser', 'OC_Share', 'removeUser'); +OC_Hook::connect('OC_User', 'post_addToGroup', 'OC_Share', 'addToGroupShare'); +OC_Hook::connect('OC_User', 'post_removeFromGroup', 'OC_Share', 'removeFromGroupShare'); +$dir = isset($_GET['dir']) ? $_GET['dir'] : '/'; +if ($dir != '/Shared' || OC_Appconfig::getValue('files_sharing', 'resharing', 'yes') == 'yes') { + OC_Util::addScript("files_sharing", "share"); +} OC_Util::addScript("3rdparty", "chosen/chosen.jquery.min"); OC_Util::addStyle( 'files_sharing', 'sharing' ); OC_Util::addStyle("3rdparty", "chosen/chosen"); diff --git a/apps/files_sharing/js/settings.js b/apps/files_sharing/js/settings.js new file mode 100644 index 00000000000..bb7d79fecbb --- /dev/null +++ b/apps/files_sharing/js/settings.js @@ -0,0 +1,9 @@ +$(document).ready(function() { + $('#allowResharing').bind('change', function() { + var checked = 1; + if (!this.checked) { + checked = 0; + } + $.post(OC.filePath('files_sharing','ajax','toggleresharing.php'), 'resharing='+checked); + }); +});
\ No newline at end of file diff --git a/apps/files_sharing/js/share.js b/apps/files_sharing/js/share.js index 54d749d833e..4125fd14d25 100644 --- a/apps/files_sharing/js/share.js +++ b/apps/files_sharing/js/share.js @@ -163,6 +163,9 @@ $(document).ready(function() { data: data, success: function(){ $('#link').hide('blind'); + $('#emailBreak').remove(); + $('#email').hide('blind'); + $('#emailButton').hide('blind'); } }); } @@ -172,6 +175,14 @@ $(document).ready(function() { $(this).focus(); $(this).select(); }); + + $('#emailButton').live('click', function() { + $('#email').css('font-weight', 'bold'); + $('#email').animate({ fontWeight: 'normal' }, 2000, function() { + $(this).val(''); + }).val('Email sent'); + $.post(OC.filePath('files_sharing','ajax','email.php'), 'toaddress='+$('#email').val()+'&link='+$('#link').val()); + }); }); function createDropdown(filename, files) { @@ -183,10 +194,12 @@ function createDropdown(filename, files) { html += '<ul id="shared_list"></ul>'; html += '</div>'; html += '<div id="public">'; - html += '<input type="checkbox" name="makelink" id="makelink" value="1" /><label for="makelink">make public</label>'; + html += '<input type="checkbox" name="makelink" id="makelink" value="1" /><label for="makelink">Share with private link</label>'; //html += '<input type="checkbox" name="public_link_write" id="public_link_write" value="1" /><label for="public_link_write">allow upload</label>'; html += '<br />'; html += '<input id="link" style="display:none; width:90%;" />'; + html += '<input id="email" style="display:none; width:65%;" value="" placeholder="Email link to person" />'; + html += '<input id="emailButton" style="display:none;" type="submit" value="Send" />'; html += '</div>'; if (filename) { $('tr').filterAttr('data-file',filename).addClass('mouseOver'); @@ -241,5 +254,9 @@ function showPublicLink(token, file) { $('#makelink').attr('checked', true); $('#link').data('token', token); $('#link').val(parent.location.protocol+'//'+location.host+OC.linkTo('files_sharing','get.php')+'?token='+token+'&f='+file); - $('#link').show('blind'); + $('#link').show('blind', function() { + $('#link').after('<br id="emailBreak" />'); + $('#email').show('blind'); + $('#emailButton').show('blind'); + }); } diff --git a/apps/files_sharing/lib_share.php b/apps/files_sharing/lib_share.php index 673984f393b..62ac05a5952 100644 --- a/apps/files_sharing/lib_share.php +++ b/apps/files_sharing/lib_share.php @@ -436,6 +436,34 @@ class OC_Share { } } + public static function removeUser($arguments) { + $query = OC_DB::prepare('DELETE FROM *PREFIX*sharing WHERE uid_owner = ? OR uid_shared_with '.self::getUsersAndGroups($arguments['uid'])); + $query->execute(array($arguments['uid'])); + } + + public static function addToGroupShare($arguments) { + $length = -strlen($arguments['gid']) - 1; + $query = OC_DB::prepare('SELECT uid_owner, source, permissions FROM *PREFIX*sharing WHERE SUBSTR(uid_shared_with, '.$length.') = ?'); + $gid = '@'.$arguments['gid']; + $result = $query->execute(array($gid))->fetchAll(); + if (count($result) > 0) { + $query = OC_DB::prepare('INSERT INTO *PREFIX*sharing VALUES(?,?,?,?,?)'); + $sharedFolder = '/'.$arguments['uid'].'/files/Shared/'; + $lastSource = ''; + for ($i = 0; $i < count($result) - 1; $i++) { + if ($result[$i]['source'] != $lastSource) { + $query->execute(array($result[$i]['uid_owner'], $arguments['uid'].'@'.$arguments['gid'], $result[$i]['source'], $sharedFolder.basename($result[$i]['source']), $result[$i]['permissions'])); + $lastSource = $result[$i]['source']; + } + } + } + } + + public static function removeFromGroupShare($arguments) { + $query = OC_DB::prepare('DELETE FROM *PREFIX*sharing WHERE uid_shared_with = ?'); + $query->execute(array($arguments['uid'].'@'.$arguments['gid'])); + } + } ?> diff --git a/apps/files_sharing/settings.php b/apps/files_sharing/settings.php new file mode 100644 index 00000000000..b30c4f45cde --- /dev/null +++ b/apps/files_sharing/settings.php @@ -0,0 +1,9 @@ +<?php + +OC_Util::checkAdminUser(); +OC_Util::addScript('files_sharing', 'settings'); +$tmpl = new OC_Template('files_sharing', 'settings'); +$tmpl->assign('allowResharing', OC_Appconfig::getValue('files_sharing', 'resharing', 'yes')); +return $tmpl->fetchPage(); + +?>
\ No newline at end of file diff --git a/apps/files_sharing/templates/settings.php b/apps/files_sharing/templates/settings.php new file mode 100644 index 00000000000..5b6ba5f33ee --- /dev/null +++ b/apps/files_sharing/templates/settings.php @@ -0,0 +1,6 @@ +<form id="resharing"> + <fieldset class="personalblock"> + <input type="checkbox" name="allowResharing" id="allowResharing" value="1" <?php if ($_['allowResharing'] == 'yes') echo ' checked="checked"'; ?> /> <label for="allowResharing"><?php echo $l->t('Enable Resharing'); ?></label> <br/> + <em><?php echo $l->t('Allow users to reshare files they don\'t own');?></em> + </fieldset> +</form>
\ No newline at end of file diff --git a/apps/files_versions/appinfo/app.php b/apps/files_versions/appinfo/app.php index 6e7a803252e..32e4c0ce81b 100644 --- a/apps/files_versions/appinfo/app.php +++ b/apps/files_versions/appinfo/app.php @@ -9,6 +9,7 @@ OC_App::register( array( 'name' => 'Versioning' )); OC_APP::registerAdmin('files_versions', 'settings'); +OC_UTIL::addScript('files_versions', 'versions'); // Listen to write signals OC_Hook::connect(OC_Filesystem::CLASSNAME, OC_Filesystem::signal_post_write, "OCA_Versions\Storage", "write_hook"); diff --git a/apps/files_versions/css/versions.css b/apps/files_versions/css/versions.css index 139597f9cb0..b2279e9b05a 100644 --- a/apps/files_versions/css/versions.css +++ b/apps/files_versions/css/versions.css @@ -1,2 +1,3 @@ - - +#history { + margin: 2em 2em 0; +}
\ No newline at end of file diff --git a/apps/files_versions/history.php b/apps/files_versions/history.php index 6c7626ca4ed..b0aa8fdc982 100644 --- a/apps/files_versions/history.php +++ b/apps/files_versions/history.php @@ -20,40 +20,41 @@ * License along with this library. If not, see <http://www.gnu.org/licenses/>. * */ -require_once('../../lib/base.php'); +require_once( '../../lib/base.php' ); -OC_Util::checkLoggedIn(); +OC_Util::checkLoggedIn( ); +OC_Util::addStyle('files_versions','versions'); -if (isset($_GET['path'])) { +if ( isset( $_GET['path'] ) ) { $path = $_GET['path']; - $path = strip_tags($path); + $path = strip_tags( $path); // roll back to old version if button clicked - if(isset($_GET['revert'])) { - \OCA_Versions\Storage::rollback($path,$_GET['revert']); + if( isset( $_GET['revert'] ) ) { + \OCA_Versions\Storage::rollback( $path, $_GET['revert'] ); } // show the history only if there is something to show - if(OCA_Versions\Storage::isversioned($path)) { + if( OCA_Versions\Storage::isversioned( $path ) ) { $count=5; //show the newest revisions - $versions=OCA_Versions\Storage::getversions($path,$count); + $versions=OCA_Versions\Storage::getversions( $path, $count); - $tmpl = new OC_Template('files_versions', 'history', 'user'); - $tmpl->assign('path', $path); - $tmpl->assign('versions', array_reverse($versions)); - $tmpl->printPage(); + $tmpl = new OC_Template( 'files_versions', 'history', 'user' ); + $tmpl->assign( 'path', $path); + $tmpl->assign( 'versions', array_reverse( $versions) ); + $tmpl->printPage( ); }else{ - $tmpl = new OC_Template('files_versions', 'history', 'user'); - $tmpl->assign('path', $path); - $tmpl->assign('message', 'No old versions available'); - $tmpl->printPage(); + $tmpl = new OC_Template( 'files_versions', 'history', 'user' ); + $tmpl->assign( 'path', $path); + $tmpl->assign( 'message', 'No old versions available' ); + $tmpl->printPage( ); } }else{ - $tmpl = new OC_Template('files_versions', 'history', 'user'); - $tmpl->assign('message', 'No path specified'); - $tmpl->printPage(); + $tmpl = new OC_Template( 'files_versions', 'history', 'user' ); + $tmpl->assign( 'message', 'No path specified' ); + $tmpl->printPage( ); } diff --git a/apps/files_versions/js/versions.js b/apps/files_versions/js/versions.js index 139597f9cb0..325ef823a9c 100644 --- a/apps/files_versions/js/versions.js +++ b/apps/files_versions/js/versions.js @@ -1,2 +1,67 @@ +$(document).ready(function(){ + + // Add history button to files/index.php + FileActions.register('file','History',function(){return OC.imagePath('core','actions/history')},function(filename){ + + if (scanFiles.scanning){return;}//workaround to prevent additional http request block scanning feedback + + var file = $('#dir').val()+'/'+filename; + + createVersionsDropdown(filename, file) + //window.location='../apps/files_versions/history.php?path='+encodeURIComponent($('#dir').val()).replace(/%2F/g, '/')+'/'+encodeURIComponent(filename); + + }); + +}); + +function createVersionsDropdown(filename, files) { + var historyUrl = '../apps/files_versions/history.php?path='+encodeURIComponent($('#dir').val()).replace(/%2F/g, '/')+'/'+encodeURIComponent(filename); + //alert( historyUrl ); + var html = '<div id="dropdown" class="drop" data-file="'+files+'">'; + html += '<div id="private">'; + html += '<select data-placeholder="File Version" id="share_with" class="chzen-select">'; + html += '<option value=""></option>'; + html += '</select>'; + html += '<ul id="shared_list"></ul>'; + html += '</div>'; + html += '<div id="public">'; + html += '<input type="button" name="makelink" id="makelink" value="Revert file" />'; + html += '<input type="button" onclick="window.location=\''+historyUrl+'\'" name="makelink" id="makelink" value="More..." />'; + html += '<br />'; + html += '<input id="link" style="display:none; width:90%;" />'; + html += '</div>'; + + if (filename) { + $('tr').filterAttr('data-file',filename).addClass('mouseOver'); + $(html).appendTo($('tr').filterAttr('data-file',filename).find('td.filename')); + } else { + $(html).appendTo($('thead .share')); + } +// $.getJSON(OC.linkTo('files_sharing', 'ajax/userautocomplete.php'), function(users) { +// if (users) { +// $.each(users, function(index, row) { +// $(row).appendTo('#share_with'); +// }); +// $('#share_with').trigger('liszt:updated'); +// } +// }); +// $.getJSON(OC.linkTo('files_sharing', 'ajax/getitem.php'), { source: files }, function(users) { +// if (users) { +// $.each(users, function(index, row) { +// if (row.uid_shared_with == 'public') { +// showPublicLink(row.token, '/'+filename); +// } else if (isNaN(index)) { +// addUser(row.uid_shared_with, row.permissions, index.substr(0, index.lastIndexOf('-'))); +// } else { +// addUser(row.uid_shared_with, row.permissions, false); +// } +// }); +// } +// }); + + $('#dropdown').show('blind'); + $('#share_with').chosen(); + +}
\ No newline at end of file diff --git a/apps/files_versions/templates/history.php b/apps/files_versions/templates/history.php index 1b3de9ce77c..d33d2b0f68b 100644 --- a/apps/files_versions/templates/history.php +++ b/apps/files_versions/templates/history.php @@ -1,3 +1,4 @@ +<div id="history"> <?php if(isset($_['message'])){ @@ -10,9 +11,10 @@ echo('<strong>Versions of '.$_['path']).'</strong><br>'; echo('<p><em>You can click on the revert button to revert to the specific verson.</em></p><br />'); foreach ($_['versions'] as $v){ - echo(' '.OC_Util::formatDate($v).' <a href="history.php?path='.urlencode($_['path']).'&revert='.$v.'" class="button">revert</a><br /><br />'); + echo(' '.OC_Util::formatDate($v).' <a href="history.php?path='.urlencode($_['path']).'&revert='.$v.'" class="button">Revert</a><br /><br />'); } } ?> +</div> diff --git a/apps/files_versions/versions.php b/apps/files_versions/versions.php index 156a4f59c73..167c64a4345 100644 --- a/apps/files_versions/versions.php +++ b/apps/files_versions/versions.php @@ -36,7 +36,7 @@ class Storage { const DEFAULTFOLDER='versions'; const DEFAULTBLACKLIST='avi mp3 mpg mp4'; const DEFAULTMAXFILESIZE=1048576; // 10MB - const DEFAULTMININTERVAL=300; // 5 min + const DEFAULTMININTERVAL=1; // 5 min const DEFAULTMAXVERSIONS=50; /** diff --git a/apps/user_ldap/appinfo/database.xml b/apps/user_ldap/appinfo/database.xml new file mode 100644 index 00000000000..74c56fcf743 --- /dev/null +++ b/apps/user_ldap/appinfo/database.xml @@ -0,0 +1,95 @@ +<?xml version="1.0" encoding="ISO-8859-1" ?> +<database> + + <name>*dbname*</name> + <create>true</create> + <overwrite>false</overwrite> + <charset>utf8</charset> + + <table> + + <name>*dbprefix*ldap_user_mapping</name> + + <declaration> + + <field> + <name>ldap_dn</name> + <type>text</type> + <notnull>true</notnull> + <length>255</length> + <default></default> + </field> + + <field> + <name>owncloud_name</name> + <type>text</type> + <notnull>true</notnull> + <length>255</length> + <default></default> + </field> + + <index> + <name>ldap_dn</name> + <unique>true</unique> + <field> + <name>ldap_dn</name> + </field> + </index> + + <index> + <name>owncloud_name</name> + <unique>true</unique> + <field> + <name>owncloud_name</name> + <sorting>ascending</sorting> + </field> + </index> + + </declaration> + + </table> + + <table> + + <name>*dbprefix*ldap_group_mapping</name> + + <declaration> + + <field> + <name>ldap_dn</name> + <type>text</type> + <notnull>true</notnull> + <length>255</length> + <default></default> + </field> + + <field> + <name>owncloud_name</name> + <type>text</type> + <notnull>true</notnull> + <length>255</length> + <default></default> + </field> + + <index> + <name>ldap_dn</name> + <unique>true</unique> + <field> + <name>ldap_dn</name> + </field> + </index> + + <index> + <name>owncloud_name</name> + <unique>true</unique> + <field> + <name>owncloud_name</name> + <sorting>ascending</sorting> + </field> + </index> + + </declaration> + + </table> + +</database>
\ No newline at end of file diff --git a/apps/user_ldap/appinfo/version b/apps/user_ldap/appinfo/version index ceab6e11ece..a0d78bd347e 100644 --- a/apps/user_ldap/appinfo/version +++ b/apps/user_ldap/appinfo/version @@ -1 +1 @@ -0.1
\ No newline at end of file +0.1.90
\ No newline at end of file diff --git a/apps/user_ldap/group_ldap.php b/apps/user_ldap/group_ldap.php index fe0789cdeb7..7773968e208 100644 --- a/apps/user_ldap/group_ldap.php +++ b/apps/user_ldap/group_ldap.php @@ -24,13 +24,9 @@ class OC_GROUP_LDAP extends OC_Group_Backend { // //group specific settings protected $ldapGroupFilter; - protected $ldapGroupDisplayName; - protected $ldapGroupMemberAttr; public function __construct() { $this->ldapGroupFilter = OC_Appconfig::getValue('user_ldap', 'ldap_group_filter', '(objectClass=posixGroup)'); - $this->ldapGroupDisplayName = OC_Appconfig::getValue('user_ldap', 'ldap_group_display_name', 'cn'); - $this->ldapGroupMemberAttr = OC_Appconfig::getValue('user_ldap', 'ldap_group_member_attr', 'memberUid'); } /** @@ -42,18 +38,17 @@ class OC_GROUP_LDAP extends OC_Group_Backend { * Checks whether the user is member of a group or not. */ public function inGroup($uid, $gid) { - $filter = OC_LDAP::combineFilterWithAnd(array( - $this->ldapGroupFilter, - LDAP_GROUP_MEMBER_ASSOC_ATTR.'='.$uid, - $this->ldapGroupDisplayName.'='.$gid - )); - $groups = $this->retrieveList($filter, $this->ldapGroupDisplayName); - - if(count($groups) > 0) { - return true; - } else { + $dn_user = OC_LDAP::username2dn($uid); + $dn_group = OC_LDAP::groupname2dn($gid); +// if($dn_group == 'c') {echo('#sdfsdgfds');die($gid);} + // just in case + if(!$dn_group || !$dn_user) { return false; } +// var_dump($dn_group); + $members = OC_LDAP::readAttribute($dn_group, LDAP_GROUP_MEMBER_ASSOC_ATTR); + + return in_array($dn_user, $members); } /** @@ -65,12 +60,19 @@ class OC_GROUP_LDAP extends OC_Group_Backend { * if the user exists at all. */ public function getUserGroups($uid) { + $userDN = OC_LDAP::username2dn($uid); + if(!$userDN) { + return array(); + } + $filter = OC_LDAP::combineFilterWithAnd(array( $this->ldapGroupFilter, - LDAP_GROUP_MEMBER_ASSOC_ATTR.'='.$uid + LDAP_GROUP_MEMBER_ASSOC_ATTR.'='.$userDN )); + $groups = $this->retrieveList($filter, array(OC_LDAP::conf('ldapGroupDisplayName'),'dn')); + $userGroups = OC_LDAP::ownCloudGroupNames($groups); - return $this->retrieveList($filter, $this->ldapGroupDisplayName); + return array_unique($userGroups, SORT_LOCALE_STRING); } /** @@ -78,12 +80,16 @@ class OC_GROUP_LDAP extends OC_Group_Backend { * @returns array with user ids */ public function usersInGroup($gid) { - $filter = OC_LDAP::combineFilterWithAnd(array( - $this->ldapGroupFilter, - $this->ldapGroupDisplayName.'='.$gid - )); - - return $this->retrieveList($filter, $this->ldapGroupMemberAttr, false); + $groupDN = OC_LDAP::groupname2dn($gid); + if(!$groupDN) { + return array(); + } + $members = OC_LDAP::readAttribute($groupDN, LDAP_GROUP_MEMBER_ASSOC_ATTR); + $result = array(); + foreach($members as $member) { + $result[] = OC_LDAP::dn2username($member); + } + return array_unique($result, SORT_LOCALE_STRING); } /** @@ -93,7 +99,9 @@ class OC_GROUP_LDAP extends OC_Group_Backend { * Returns a list with all groups */ public function getGroups() { - return $this->retrieveList($this->ldapGroupFilter, $this->ldapGroupDisplayName); + $ldap_groups = $this->retrieveList($this->ldapGroupFilter, array(OC_LDAP::conf('ldapGroupDisplayName'), 'dn')); + $groups = OC_LDAP::ownCloudGroupNames($ldap_groups); + return $groups; } /** @@ -112,13 +120,18 @@ class OC_GROUP_LDAP extends OC_Group_Backend { $list = OC_LDAP::searchUsers($filter, $attr); } - if(is_array($list)) { - return array_unique($list, SORT_LOCALE_STRING); + if(count($attr) > 1){ + return $list; + } else { + return array_unique($list, SORT_LOCALE_STRING); + } } //error cause actually, maybe throw an exception in future. return array(); } + + }
\ No newline at end of file diff --git a/apps/user_ldap/js/settings.js b/apps/user_ldap/js/settings.js new file mode 100644 index 00000000000..cae9655e3df --- /dev/null +++ b/apps/user_ldap/js/settings.js @@ -0,0 +1,3 @@ +$(document).ready(function() { + $('#ldapSettings').tabs(); +});
\ No newline at end of file diff --git a/apps/user_ldap/lib_ldap.php b/apps/user_ldap/lib_ldap.php index 752ac4f2289..4efcf0c5a0d 100644 --- a/apps/user_ldap/lib_ldap.php +++ b/apps/user_ldap/lib_ldap.php @@ -21,7 +21,8 @@ * */ -define('LDAP_GROUP_MEMBER_ASSOC_ATTR','memberUid'); +define('LDAP_GROUP_MEMBER_ASSOC_ATTR','uniqueMember'); +define('LDAP_GROUP_DISPLAY_NAME_ATTR','cn'); //needed to unbind, because we use OC_LDAP only statically class OC_LDAP_DESTRUCTOR { @@ -45,7 +46,9 @@ class OC_LDAP { static protected $ldapTLS; static protected $ldapNoCase; // user and group settings, that are needed in both backends - static public $ldapUserDisplayName; + static protected $ldapUserDisplayName; + static protected $ldapUserFilter; + static protected $ldapGroupDisplayName; static public function init() { self::readConfiguration(); @@ -56,14 +59,345 @@ class OC_LDAP { @ldap_unbind(self::$ldapConnectionRes); } + /** + * @brief returns a read-only configuration value + * @param $key the name of the configuration value + * @returns the value on success, otherwise null + * + * returns a read-only configuration values + * + * we cannot work with getters, because it is a static class + */ static public function conf($key) { + if(!self::$configured) { + self::init(); + } + $availableProperties = array( 'ldapUserDisplayName', + 'ldapGroupDisplayName', ); if(in_array($key, $availableProperties)) { return self::$$key; } + + return null; + } + + /** + * gives back the database table for the query + */ + static private function getMapTable($isUser) { + if($isUser) { + return '*PREFIX*ldap_user_mapping'; + } else { + return '*PREFIX*ldap_group_mapping'; + } + } + + /** + * @brief returns the LDAP DN for the given internal ownCloud name of the group + * @param $name the ownCloud name in question + * @returns string with the LDAP DN on success, otherwise false + * + * returns the LDAP DN for the given internal ownCloud name of the group + */ + static public function groupname2dn($name) { + return self::ocname2dn($name, false); + } + + /** + * @brief returns the LDAP DN for the given internal ownCloud name of the user + * @param $name the ownCloud name in question + * @returns string with the LDAP DN on success, otherwise false + * + * returns the LDAP DN for the given internal ownCloud name of the user + */ + static public function username2dn($name) { + $dn = self::ocname2dn($name, true); + if($dn) { + return $dn; + } else { + //fallback: user is not mapped + $filter = self::combineFilterWithAnd(array( + self::$ldapUserFilter, + self::$ldapUserDisplayName . '=' . $name, + )); + $result = self::searchUsers($filter, 'dn'); + if(isset($result[0]['dn'])) { + self::mapUser($result[0], $name); + return $result[0]; + } + } + + return false; + } + + static private function ocname2dn($name, $isUser) { + $table = self::getMapTable($isUser); + + $query = OC_DB::prepare(' + SELECT ldap_dn + FROM '.$table.' + WHERE owncloud_name = ? + '); + + $record = $query->execute(array($name))->fetchOne(); + return $record; + if($name=='Coyotes') { + echo("adsfasdf "); + var_dump($record); + die(); + } + if(isset($record['ldap_dn'])) { + return $record['ldap_dn']; + } + + return false; + } + + /** + * @brief returns the internal ownCloud name for the given LDAP DN of the group + * @param $dn the dn of the group object + * @param $ldapname optional, the display name of the object + * @returns string with with the name to use in ownCloud + * + * returns the internal ownCloud name for the given LDAP DN of the group + */ + static public function dn2groupname($dn, $ldapname = null) { + return self::dn2ocname($dn, $ldapname, false); + } + + /** + * @brief returns the internal ownCloud name for the given LDAP DN of the user + * @param $dn the dn of the user object + * @param $ldapname optional, the display name of the object + * @returns string with with the name to use in ownCloud + * + * returns the internal ownCloud name for the given LDAP DN of the user + */ + static public function dn2username($dn, $ldapname = null) { + return self::dn2ocname($dn, $ldapname, true); + } + + static public function dn2ocname($dn, $ldapname = null, $isUser = true) { + $table = self::getMapTable($isUser); + if($isUser) { + $nameAttribute = self::conf('ldapUserDisplayName'); + } else { + $nameAttribute = self::conf('ldapGroupDisplayName'); + } + + $query = OC_DB::prepare(' + SELECT owncloud_name + FROM '.$table.' + WHERE ldap_dn = ? + '); + + $component = $query->execute(array($dn))->fetchOne(); + if($component) { + return $component; + } + + if(is_null($ldapname)) { + $ldapname = self::readAttribute($dn, $nameAttribute); + $ldapname = $ldapname[0]; + } + + //a new user/group! Then let's try to add it. We're shooting into the blue with the user/group name, assuming that in most cases there will not be a conflict. Otherwise an error will occur and we will continue with our second shot. + if(self::mapComponent($dn, $ldapname, $isUser)) { + return $ldapname; + } + + //doh! There is a conflict. We need to distinguish between users/groups. Adding indexes is an idea, but not much of a help for the user. The DN is ugly, but for now the only reasonable way. But we transform it to a readable format and remove the first part to only give the path where this object is located. + $oc_name = self::alternateOwnCloudName($ldapname, $dn); + if(self::mapComponent($dn, $oc_name, $isUser)) { + return $oc_name; + } + + //and this of course should never been thrown :) + throw new Exception('LDAP backend: unexpected collision of DN and ownCloud Name.'); + } + + /** + * @brief gives back the user names as they are used ownClod internally + * @param $ldapGroups an array with the ldap Users result in style of array ( array ('dn' => foo, 'uid' => bar), ... ) + * @returns an array with the user names to use in ownCloud + * + * gives back the user names as they are used ownClod internally + */ + static public function ownCloudUserNames($ldapUsers) { + return self::ldap2ownCloudNames($ldapUsers, true); + } + + /** + * @brief gives back the group names as they are used ownClod internally + * @param $ldapGroups an array with the ldap Groups result in style of array ( array ('dn' => foo, 'cn' => bar), ... ) + * @returns an array with the group names to use in ownCloud + * + * gives back the group names as they are used ownClod internally + */ + static public function ownCloudGroupNames($ldapGroups) { + return self::ldap2ownCloudNames($ldapGroups, false); + } + + static private function ldap2ownCloudNames($ldapObjects, $isUsers) { + if($isUsers) { + $knownObjects = self::mappedUsers(); + $nameAttribute = self::conf('ldapUserDisplayName'); + } else { + $knownObjects = self::mappedGroups(); + $nameAttribute = self::conf('ldapGroupDisplayName'); + } + $ownCloudNames = array(); + + foreach($ldapObjects as $ldapObject) { + $key = self::recursiveArraySearch($knownObjects, $ldapObject['dn']); + + //everything is fine when we know the group + if($key) { + $ownCloudNames[] = $knownObjects[$key]['owncloud_name']; + continue; + } + + //a new group! Then let's try to add it. We're shooting into the blue with the group name, assuming that in most cases there will not be a conflict + if(self::mapComponent($ldapObject['dn'], $ldapObject[$nameAttribute], $isUsers)) { + $ownCloudNames[] = $ldapObject[$nameAttribute]; + continue; + } + + //doh! There is a conflict. We need to distinguish between groups. Adding indexes is an idea, but not much of a help for the user. The DN is ugly, but for now the only reasonable way. But we transform it to a readable format and remove the first part to only give the path where this entry is located. + $oc_name = self::alternateOwnCloudName($ldapObject[$nameAttribute], $ldapObject['dn']); + if(self::mapComponent($ldapObject['dn'], $oc_name, $isUsers)) { + $ownCloudNames[] = $oc_name; + continue; + } + + //and this of course should never been thrown :) + throw new Exception('LDAP backend: unexpected collision of DN and ownCloud Name.'); + } + return $ownCloudNames; + } + + /** + * @brief creates a hopefully unique name for owncloud based on the display name and the dn of the LDAP object + * @param $name the display name of the object + * @param $dn the dn of the object + * @returns string with with the name to use in ownCloud + * + * creates a hopefully unique name for owncloud based on the display name and the dn of the LDAP object + */ + static private function alternateOwnCloudName($name, $dn) { + $ufn = ldap_dn2ufn($dn); + return $name . ' (' . trim(substr_replace($ufn, '', 0, strpos($ufn, ','))) . ')'; + } + + /** + * @brief retrieves all known groups from the mappings table + * @returns array with the results + * + * retrieves all known groups from the mappings table + */ + static private function mappedGroups() { + return self::mappedComponents(false); + } + + /** + * @brief retrieves all known users from the mappings table + * @returns array with the results + * + * retrieves all known users from the mappings table + */ + static private function mappedUsers() { + return self::mappedComponents(true); + } + + static private function mappedComponents($isUsers) { + $table = self::getMapTable($isUsers); + + $query = OC_DB::prepare(' + SELECT ldap_dn, owncloud_name + FROM '. $table + ); + + return $query->execute()->fetchAll(); + } + + /** + * @brief inserts a new group into the mappings table + * @param $dn the record in question + * @param $ocname the name to use in ownCloud + * @returns true on success, false otherwise + * + * inserts a new group into the mappings table + */ + static private function mapGroup($dn, $ocname) { + return self::mapComponent($dn, $ocname, false); + } + + /** + * @brief inserts a new user into the mappings table + * @param $dn the record in question + * @param $ocname the name to use in ownCloud + * @returns true on success, false otherwise + * + * inserts a new user into the mappings table + */ + static private function mapUser($dn, $ocname) { + return self::mapComponent($dn, $ocname, true); + } + + /** + * @brief inserts a new user or group into the mappings table + * @param $dn the record in question + * @param $ocname the name to use in ownCloud + * @param $isUser is it a user or a group? + * @returns true on success, false otherwise + * + * inserts a new user or group into the mappings table + */ + static private function mapComponent($dn, $ocname, $isUser = true) { + $table = self::getMapTable($isUser); + + $insert = OC_DB::prepare(' + INSERT IGNORE INTO '.$table.' + (ldap_dn, owncloud_name) + VALUES (?,?) + '); + + $res = $insert->execute(array($dn, $ocname)); + + return !OC_DB::isError($res); + } + + /** + * @brief reads a given attribute for an LDAP record identified by a DN + * @param $dn the record in question + * @param $attr the attribute that shall be retrieved + * @returns the values in an array on success, false otherwise + * + * Reads an attribute from an LDAP entry + */ + static public function readAttribute($dn, $attr) { + $cr = self::getConnectionResource(); +// echo("<pre>");var_dump($dn); + $rr = ldap_read($cr, $dn, 'objectClass=*', array($attr)); + if(!$rr) { + echo('<pre>###RA ');var_dump($dn);var_dump(debug_backtrace());die(); + } + $er = ldap_first_entry($cr, $rr); + $result = ldap_get_attributes($cr, $er); + +// if($dn == 'cn=Coyotes,cn=groups,dc=blizzz-oc,dc=bzoc') die((var_dump($result))); + if($result[$attr]['count'] > 0){ + $values = array(); + for($i=0;$i<$result[$attr]['count'];$i++) { + $values[] = $result[$attr][$i]; + } + return $values; + } + return false; } /** @@ -100,15 +434,38 @@ class OC_LDAP { * Executes an LDAP search */ static private function search($filter, $base, $attr = null) { - $sr = ldap_search(self::getConnectionResource(), $base, $filter, array($attr)); + if(!is_null($attr) && !is_array($attr)) { + $attr = array(strtolower($attr)); + } + $sr = ldap_search(self::getConnectionResource(), $base, $filter, $attr); $findings = ldap_get_entries(self::getConnectionResource(), $sr ); if(!is_null($attr)) { $selection = array(); + $multiarray = false; + if(count($attr) > 1) { + $multiarray = true; + $i = 0; + } foreach($findings as $item) { - if(isset($item[strtolower($attr)])) { - $selection[] = $item[strtolower($attr)][0]; + if($multiarray) { + foreach($attr as $key) { + if(isset($item[$key])) { + if($key != 'dn'){ + $selection[$i][$key] = $item[$key][0]; + } else { + $selection[$i][$key] = $item[$key]; + } + } + + } + $i++; + } else { + if(isset($item[$attr[0]])) { + $selection[] = $item[$attr[0]]; + } } + } return $selection; } @@ -173,16 +530,18 @@ class OC_LDAP { */ static private function readConfiguration() { if(!self::$configured) { - self::$ldapHost = OC_Appconfig::getValue('user_ldap', 'ldap_host', ''); - self::$ldapPort = OC_Appconfig::getValue('user_ldap', 'ldap_port', OC_USER_BACKEND_LDAP_DEFAULT_PORT); - self::$ldapAgentName = OC_Appconfig::getValue('user_ldap', 'ldap_dn',''); - self::$ldapAgentPassword = OC_Appconfig::getValue('user_ldap', 'ldap_password',''); - self::$ldapBase = OC_Appconfig::getValue('user_ldap', 'ldap_base', ''); - self::$ldapBaseUsers = OC_Appconfig::getValue('user_ldap', 'ldap_base_users',self::$ldapBase); - self::$ldapBaseGroups = OC_Appconfig::getValue('user_ldap', 'ldap_base_groups', self::$ldapBase); - self::$ldapTLS = OC_Appconfig::getValue('user_ldap', 'ldap_tls',0); - self::$ldapNoCase = OC_Appconfig::getValue('user_ldap', 'ldap_nocase', 0); - self::$ldapUserDisplayName = OC_Appconfig::getValue('user_ldap', 'ldap_display_name', OC_USER_BACKEND_LDAP_DEFAULT_DISPLAY_NAME); + self::$ldapHost = OC_Appconfig::getValue('user_ldap', 'ldap_host', ''); + self::$ldapPort = OC_Appconfig::getValue('user_ldap', 'ldap_port', OC_USER_BACKEND_LDAP_DEFAULT_PORT); + self::$ldapAgentName = OC_Appconfig::getValue('user_ldap', 'ldap_dn',''); + self::$ldapAgentPassword = OC_Appconfig::getValue('user_ldap', 'ldap_password',''); + self::$ldapBase = OC_Appconfig::getValue('user_ldap', 'ldap_base', ''); + self::$ldapBaseUsers = OC_Appconfig::getValue('user_ldap', 'ldap_base_users',self::$ldapBase); + self::$ldapBaseGroups = OC_Appconfig::getValue('user_ldap', 'ldap_base_groups', self::$ldapBase); + self::$ldapTLS = OC_Appconfig::getValue('user_ldap', 'ldap_tls',0); + self::$ldapNoCase = OC_Appconfig::getValue('user_ldap', 'ldap_nocase', 0); + self::$ldapUserDisplayName = OC_Appconfig::getValue('user_ldap', 'ldap_display_name', OC_USER_BACKEND_LDAP_DEFAULT_DISPLAY_NAME); + self::$ldapUserFilter = OC_Appconfig::getValue('user_ldap', 'ldap_userlist_filter','objectClass=person'); + self::$ldapGroupDisplayName = OC_Appconfig::getValue('user_ldap', 'ldap_group_display_name', LDAP_GROUP_DISPLAY_NAME_ATTR); if( !empty(self::$ldapHost) @@ -226,5 +585,23 @@ class OC_LDAP { } } + /** + * taken from http://www.php.net/manual/en/function.array-search.php#97645 + * TODO: move somewhere, where its better placed since it is not LDAP specific. OC_Helper maybe? + */ + static public function recursiveArraySearch($haystack, $needle, $index = null) { + $aIt = new RecursiveArrayIterator($haystack); + $it = new RecursiveIteratorIterator($aIt); + + while($it->valid()) { + if (((isset($index) AND ($it->key() == $index)) OR (!isset($index))) AND ($it->current() == $needle)) { + return $aIt->key(); + } + + $it->next(); + } + + return false; + } }
\ No newline at end of file diff --git a/apps/user_ldap/settings.php b/apps/user_ldap/settings.php index ad44fe95f9e..2226c74609d 100644 --- a/apps/user_ldap/settings.php +++ b/apps/user_ldap/settings.php @@ -20,7 +20,10 @@ * License along with this library. If not, see <http://www.gnu.org/licenses/>. * */ -$params = array('ldap_host', 'ldap_port', 'ldap_dn', 'ldap_password', 'ldap_base', 'ldap_userlist_filter', 'ldap_login_filter', 'ldap_display_name', 'ldap_tls', 'ldap_nocase'. 'ldap_quota_def', 'ldap_quota_attr', 'ldap_email_attr'); +$params = array('ldap_host', 'ldap_port', 'ldap_dn', 'ldap_password', 'ldap_base', 'ldap_base_users', 'ldap_base_groups', 'ldap_userlist_filter', 'ldap_login_filter', 'ldap_display_name', 'ldap_tls', 'ldap_nocase'. 'ldap_quota_def', 'ldap_quota_attr', 'ldap_email_attr'); + +OC_Util::addScript('user_ldap', 'settings'); +OC_Util::addStyle('user_ldap', 'settings'); if ($_POST) { foreach($params as $param){ @@ -45,10 +48,8 @@ foreach($params as $param){ $tmpl->assign($param, $value); } -// ldap_port has a default value +// settings with default values $tmpl->assign( 'ldap_port', OC_Appconfig::getValue('user_ldap', 'ldap_port', OC_USER_BACKEND_LDAP_DEFAULT_PORT)); - -// ldap_display_name has a default value $tmpl->assign( 'ldap_display_name', OC_Appconfig::getValue('user_ldap', 'ldap_display_name', OC_USER_BACKEND_LDAP_DEFAULT_DISPLAY_NAME)); return $tmpl->fetchPage(); diff --git a/apps/user_ldap/templates/settings.php b/apps/user_ldap/templates/settings.php index 828c72cba97..7e327bb0701 100644 --- a/apps/user_ldap/templates/settings.php +++ b/apps/user_ldap/templates/settings.php @@ -1,21 +1,30 @@ <form id="ldap" action="#" method="post"> - <fieldset class="personalblock"> - <legend><strong>LDAP</strong></legend> - <p><label for="ldap_host"><?php echo $l->t('Host');?><input type="text" id="ldap_host" name="ldap_host" value="<?php echo $_['ldap_host']; ?>"></label> - <label for="ldap_port"><?php echo $l->t('Port');?></label><input type="text" id="ldap_port" name="ldap_port" value="<?php echo $_['ldap_port']; ?>" /></p> + <div id="ldapSettings" class="personalblock"> + <ul> + <li><a href="#ldapSettings-1">LDAP Basic</a></li> + <li><a href="#ldapSettings-2">Advanced</a></li> + </ul> + <fieldset id="ldapSettings-1"> + <p><label for="ldap_host"><?php echo $l->t('Host');?><input type="text" id="ldap_host" name="ldap_host" value="<?php echo $_['ldap_host']; ?>"></label> <label for="ldap_base"><?php echo $l->t('Base');?></label><input type="text" id="ldap_base" name="ldap_base" value="<?php echo $_['ldap_base']; ?>" /></p> <p><label for="ldap_dn"><?php echo $l->t('Name');?></label><input type="text" id="ldap_dn" name="ldap_dn" value="<?php echo $_['ldap_dn']; ?>" /> <label for="ldap_password"><?php echo $l->t('Password');?></label><input type="password" id="ldap_password" name="ldap_password" value="<?php echo $_['ldap_password']; ?>" /> <small><?php echo $l->t('Leave both empty for anonymous bind for search, then bind with users credentials.');?></small></p> - <p><label for="ldap_base"><?php echo $l->t('Base');?></label><input type="text" id="ldap_base" name="ldap_base" value="<?php echo $_['ldap_base']; ?>" /></p> <p><label for="ldap_login_filter"><?php echo $l->t('User Login Filter');?></label><input type="text" id="ldap_login_filter" name="ldap_login_filter" value="<?php echo $_['ldap_login_filter']; ?>" /><small><?php echo $l->t('use %%uid placeholder, e.g. uid=%%uid');?></small></p> - <p><label for="ldap_userlist_filter"><?php echo $l->t('User List Filter');?></label><input type="text" id="ldap_userlist_filter" name="ldap_userlist_filter" value="<?php echo $_['ldap_userlist_filter']; ?>" /><small><?php echo $l->t('without any placeholder, e.g. "objectClass=person".');?> </p> - <p><label for="ldap_display_name"><?php echo $l->t('Display Name Field');?></label><input type="text" id="ldap_display_name" name="ldap_display_name" value="<?php echo $_['ldap_display_name']; ?>" /> - <small><?php echo $l->t('Currently the display name field needs to be the same you matched %%uid against in the filter above, because ownCloud doesn\'t distinguish between user id and user name.');?></small></p> + <p><label for="ldap_userlist_filter"><?php echo $l->t('User List Filter');?></label><input type="text" id="ldap_userlist_filter" name="ldap_userlist_filter" value="<?php echo $_['ldap_userlist_filter']; ?>" /><small><?php echo $l->t('without any placeholder, e.g. "objectClass=person".');?></small></p> + </fieldset> + <fieldset id="ldapSettings-2"> + <p><label for="ldap_port"><?php echo $l->t('Port');?></label><input type="text" id="ldap_port" name="ldap_port" value="<?php echo $_['ldap_port']; ?>" /></p> + <p><label for="ldap_base_users"><?php echo $l->t('Base User Tree');?></label><input type="text" id="ldap_base_users" name="ldap_base_users" value="<?php echo $_['ldap_base_users']; ?>" /></p> + <p><label for="ldap_base_groups"><?php echo $l->t('Base Group Tree');?></label><input type="text" id="ldap_base_groups" name="ldap_base_groups" value="<?php echo $_['ldap_base_groups']; ?>" /></p> <p><input type="checkbox" id="ldap_tls" name="ldap_tls" value="1"<?php if ($_['ldap_tls']) echo ' checked'; ?>><label for="ldap_tls"><?php echo $l->t('Use TLS');?></label></p> <p><input type="checkbox" id="ldap_nocase" name="ldap_nocase" value="1"<?php if ($_['ldap_nocase']) echo ' checked'; ?>><label for="ldap_nocase"><?php echo $l->t('Case insensitve LDAP server (Windows)');?></label></p> + <p><label for="ldap_display_name"><?php echo $l->t('Display Name Field');?></label><input type="text" id="ldap_display_name" name="ldap_display_name" value="<?php echo $_['ldap_display_name']; ?>" /> + <small><?php echo $l->t('Currently the display name field needs to be the same you matched %%uid against in the filter above, because ownCloud doesn\'t distinguish between user id and user name.');?></small></p> <p><label for="ldap_quota_attr">Quota Attribute</label><input type="text" id="ldap_quota_attr" name="ldap_quota_attr" value="<?php echo $_['ldap_quota_attr']; ?>" /> - <label for="ldap_quota_def">Quota Default</label><input type="text" id="ldap_quota_def" name="ldap_quota_def" value="<?php echo $_['ldap_quota_def']; ?>" />bytes</p> - <p><label for="ldap_email_attr">Email Attribute</label><input type="text" id="ldap_email_attr" name="ldap_email_attr" value="<?php echo $_['ldap_email_attr']; ?>" /></p> - <input type="submit" value="Save" /> + <label for="ldap_quota_def">Quota Default</label><input type="text" id="ldap_quota_def" name="ldap_quota_def" value="<?php echo $_['ldap_quota_def']; ?>" />bytes</p> + <p><label for="ldap_email_attr">Email Attribute</label><input type="text" id="ldap_email_attr" name="ldap_email_attr" value="<?php echo $_['ldap_email_attr']; ?>" /></p> </fieldset> + <input type="submit" value="Save" /> + </div> + </form> |