From 496c1581d76a920fb6c6a50bc080c936d6ffbd31 Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Thu, 16 Feb 2012 23:24:23 +0100 Subject: [PATCH 001/132] ETags must be quoted. --- lib/response.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/response.php b/lib/response.php index 2fa0a5adcd..9431d7af1c 100644 --- a/lib/response.php +++ b/lib/response.php @@ -85,7 +85,7 @@ class OC_Response { self::setStatus(self::STATUS_NOT_MODIFIED); exit; } - header('ETag: '.$etag); + header('ETag: "'.$etag.'"'); } static public function setLastModifiedHeader($lastModified) { From 98b2d2db3dfb4a4ae286b0773b2297296c2cb70f Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Fri, 17 Feb 2012 09:35:18 +0100 Subject: [PATCH 002/132] Removed obsolete commented code and made minor speed improvements. Added stub function for loading categories. --- apps/contacts/js/contacts.js | 63 +++++++----------------- apps/contacts/templates/part.contact.php | 53 -------------------- 2 files changed, 17 insertions(+), 99 deletions(-) diff --git a/apps/contacts/js/contacts.js b/apps/contacts/js/contacts.js index 3079362574..c9d1dc30f0 100644 --- a/apps/contacts/js/contacts.js +++ b/apps/contacts/js/contacts.js @@ -117,7 +117,7 @@ Contacts={ $('#carddav_url_close').show(); }, messageBox:function(title, msg) { - if(msg.toLowerCase().indexOf('auth') > 0) { + if(msg.toLowerCase().indexOf('auth') != -1) { // fugly hack, I know alert(msg); } @@ -335,17 +335,6 @@ Contacts={ // Load first in list. if($('#contacts li').length > 0) { Contacts.UI.Card.update(); - /* - var firstid = $('#contacts li:first-child').data('id'); - console.log('trying to load: ' + firstid); - $.getJSON(OC.filePath('contacts', 'ajax', 'contactdetails.php'),{'id':firstid},function(jsondata){ - if(jsondata.status == 'success'){ - Contacts.UI.Card.loadContact(jsondata.data); - } - else{ - Contacts.UI.messageBox(t('contacts', 'Error'), jsondata.data.message); - } - });*/ } else { // load intro page $.getJSON('ajax/loadintro.php',{},function(jsondata){ @@ -374,6 +363,7 @@ Contacts={ $('#rightcontent').data('id',this.id); //console.log('loaded: ' + this.data.FN[0]['value']); this.populateNameFields(); + this.loadCategories(); this.loadPhoto(); this.loadMails(); this.loadPhones(); @@ -455,9 +445,6 @@ Contacts={ this.fullname += ', ' + this.honsuf; } $('#n').html(this.fullname); - //$('.jecEditableOption').attr('title', 'Custom'); - //$('.jecEditableOption').text(this.fn); - //$('.jecEditableOption').attr('value', 0); $('#fn_select option').remove(); $('#fn_select').combobox('value', this.fn); var names = [this.fullname, this.givname + ' ' + this.famname, this.famname + ' ' + this.givname, this.famname + ', ' + this.givname]; @@ -466,17 +453,16 @@ Contacts={ .append($('') .text(value)); }); - /*$('#full').text(this.fullname); - $('#short').text(this.givname + ' ' + this.famname); - $('#reverse').text(this.famname + ' ' + this.givname); - $('#reverse_comma').text(this.famname + ', ' + this.givname);*/ $('#contact_identity').find('*[data-element="N"]').data('checksum', this.data.N[0]['checksum']); $('#contact_identity').find('*[data-element="FN"]').data('checksum', this.data.FN[0]['checksum']); $('#contact_identity').show(); }, + loadCategories:function(){ + if(this.data.CATEGORIES) { + // + } + }, editNew:function(){ // add a new contact - //Contacts.UI.notImplemented(); - //return false; this.id = ''; this.fn = ''; this.fullname = ''; this.givname = ''; this.famname = ''; this.addname = ''; this.honpre = ''; this.honsuf = ''; $.getJSON('ajax/newcontact.php',{},function(jsondata){ if(jsondata.status == 'success'){ @@ -713,12 +699,6 @@ Contacts={ .text(value)); }); - /*$('#short').text(n[1] + ' ' + n[0]); - $('#full').text(this.fullname); - $('#reverse').text(n[0] + ' ' + n[1]); - $('#reverse_comma').text(n[0] + ', ' + n[1]);*/ - //$('#n').html(full); - //$('#fn').val(0); if(this.id == '') { var aid = $(dlg).find('#aid').val(); Contacts.UI.Card.add(n.join(';'), $('#short').text(), aid); @@ -889,21 +869,22 @@ Contacts={ }, loadPhoto:function(){ if(this.data.PHOTO) { + $.getJSON('ajax/loadphoto.php',{'id':this.id},function(jsondata){ + if(jsondata.status == 'success'){ + //alert(jsondata.data.page); + $('#contacts_details_photo_wrapper').html(jsondata.data.page); + } + else{ + Contacts.UI.messageBox(jsondata.data.message); + } + }); $('#file_upload_form').show(); $('#contacts_propertymenu a[data-type="PHOTO"]').parent().hide(); } else { + $('#contacts_details_photo_wrapper').empty(); $('#file_upload_form').hide(); $('#contacts_propertymenu a[data-type="PHOTO"]').parent().show(); } - $.getJSON('ajax/loadphoto.php',{'id':this.id},function(jsondata){ - if(jsondata.status == 'success'){ - //alert(jsondata.data.page); - $('#contacts_details_photo_wrapper').html(jsondata.data.page); - } - else{ - Contacts.UI.messageBox(jsondata.data.message); - } - }); }, editPhoto:function(id, tmp_path){ //alert('editPhoto: ' + tmp_path); @@ -1143,13 +1124,6 @@ $(document).ready(function(){ return false; }); - /** - * Open blank form to add new contact. - * FIXME: Load the same page but only show name data and popup the name edit dialog. - * On save load the page again with an id and show all fields. - * NOTE: Or: Load the full page and popup name dialog modal. On success set the newly aquired ID, on - * Cancel or failure give appropriate message and show ... something else :-P - */ $('#contacts_newcontact').click(function(){ Contacts.UI.Card.editNew(); }); @@ -1175,9 +1149,6 @@ $(document).ready(function(){ return false; }); - /** - * Delete currently selected contact TODO: and clear page - */ $('#contacts_deletecard').live('click',function(){ Contacts.UI.Card.delete(); }); diff --git a/apps/contacts/templates/part.contact.php b/apps/contacts/templates/part.contact.php index 408b595dc9..5be20964f4 100644 --- a/apps/contacts/templates/part.contact.php +++ b/apps/contacts/templates/part.contact.php @@ -70,14 +70,6 @@ $id = isset($_['id']) ? $_['id'] : ''; - -
  • - /> - -
  • - @@ -93,17 +85,6 @@ $id = isset($_['id']) ? $_['id'] : ''; - -
  • - /> - - -
  • - @@ -118,40 +99,6 @@ $id = isset($_['id']) ? $_['id'] : '';
      - -
      -
      - - - - 0) { - //array_walk($address['parameters'], ) Nah, this wont work... - $translated = array(); - foreach($address['parameters'] as $type) { - $translated[] = $l->t(ucwords(strtolower($type))); - } - echo implode('/', $translated); - } - ?> -
      -
      -
        - '.$adr[0].'':''); - $tmp .= ($adr[1]?'
      • '.$adr[1].'
      • ':''); - $tmp .= ($adr[2]?'
      • '.$adr[2].'
      • ':''); - $tmp .= ($adr[3]||$adr[5]?'
      • '.$adr[5].' '.$adr[3].'
      • ':''); - $tmp .= ($adr[4]?'
      • '.$adr[4].'
      • ':''); - $tmp .= ($adr[6]?'
      • '.$adr[6].'
      • ':''); - echo $tmp; - - ?> -
      -
      -
      - From 6e35d50cbb7b131bdc4bb245e3dc80042d4d8f99 Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Fri, 17 Feb 2012 19:04:12 +0100 Subject: [PATCH 003/132] Avoid errors from missing GD library. --- apps/contacts/photo.php | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/apps/contacts/photo.php b/apps/contacts/photo.php index 8dfbcb6fb1..298f1215e3 100644 --- a/apps/contacts/photo.php +++ b/apps/contacts/photo.php @@ -13,10 +13,19 @@ require_once('../../lib/base.php'); OC_Util::checkLoggedIn(); OC_Util::checkAppEnabled('contacts'); +function getStandardImage(){ + OC_Response::setExpiresHeader('P10D'); + OC_Response::enableCaching(); + OC_Response::redirect(OC_Helper::imagePath('contacts', 'person_large.png')); +} + $id = $_GET['id']; $contact = OC_Contacts_App::getContactVCard($id); $image = new OC_Image(); +if(!$image) { + getStandardImage(); +} // invalid vcard if( is_null($contact)) { OC_Log::write('contacts','photo.php. The VCard for ID '.$id.' is not RFC compatible',OC_Log::ERROR); @@ -45,7 +54,8 @@ if( is_null($contact)) { } if (!$image->valid()) { // Not found :-( - $image->loadFromFile('img/person_large.png'); + getStandardImage(); + //$image->loadFromFile('img/person_large.png'); } header('Content-Type: '.$image->mimeType()); $image->show(); From a3e58157eeb51eea414d6320cccc7188cb5995d4 Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Sat, 18 Feb 2012 11:42:58 +0100 Subject: [PATCH 004/132] Strip tags on address on client side. --- apps/contacts/js/contacts.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/contacts/js/contacts.js b/apps/contacts/js/contacts.js index c9d1dc30f0..d33f983a42 100644 --- a/apps/contacts/js/contacts.js +++ b/apps/contacts/js/contacts.js @@ -815,7 +815,7 @@ Contacts={ checksum = Contacts.UI.checksumFor(obj); container = Contacts.UI.propertyContainerFor(obj); } - var adr = new Array($(dlg).find('#adr_pobox').val(),$(dlg).find('#adr_extended').val(),$(dlg).find('#adr_street').val(),$(dlg).find('#adr_city').val(),$(dlg).find('#adr_region').val(),$(dlg).find('#adr_zipcode').val(),$(dlg).find('#adr_country').val()); + var adr = new Array($(dlg).find('#adr_pobox').val().strip_tags(),$(dlg).find('#adr_extended').val().strip_tags(),$(dlg).find('#adr_street').val().strip_tags(),$(dlg).find('#adr_city').val().strip_tags(),$(dlg).find('#adr_region').val().strip_tags(),$(dlg).find('#adr_zipcode').val().strip_tags(),$(dlg).find('#adr_country').val().strip_tags()); $(container).find('.adr').val(adr.join(';')); $(container).find('.adr_type').val($(dlg).find('#adr_type').val()); $(container).find('.adr_type_label').html(t('contacts',ucwords($(dlg).find('#adr_type').val().toLowerCase()))); From 0203f55fbfc985ea45ffff375b356d6ab0795336 Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Sat, 18 Feb 2012 11:45:36 +0100 Subject: [PATCH 005/132] Added first draft of OC_VCategories. --- lib/vcategories.php | 198 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 198 insertions(+) create mode 100644 lib/vcategories.php diff --git a/lib/vcategories.php b/lib/vcategories.php new file mode 100644 index 0000000000..69955d109a --- /dev/null +++ b/lib/vcategories.php @@ -0,0 +1,198 @@ + +* +* 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 . +* +*/ + + +/** + * Class for easy access to categories in VCARD, VEVENT, VTODO and VJOURNAL. + * A Category can be e.g. 'Family', 'Work', 'Chore', 'Special Occation' or anything else + * that is either parsed from a vobject or that the user chooses to add. + * Category names are not case-sensitive, but will be saved with the case they are + * entered in. If a user already has a category 'family' for an app, and tries to add + * a category named 'Family' it will be silently ignored. + */ +OC_HOOK::connect('OC_User', 'post_deleteUser', 'OC_VCategories', 'deleteUser'); +class OC_VCategories { + /** + * cache + */ + protected static $cache = array(); + + /** + * Categories + */ + private $categories = array(); + + /** + * @brief Constructor. + * @param $app The application identifier e.g. 'contacts' or 'calendar'. + */ + public function __construct($app, $user=null) { + if(is_null($user)) { + $user = OC_User::getUser(); + } + // Use cache if possible - I doubt this is ever the case. Copy/paste from OC_L10N. + if(array_key_exists($app.'::'.$user, self::$cache)){ + OC_Log::write('core','OC_Categories::ctor, using cache', OC_Log::DEBUG); + $this->categories = self::$cache[$app.'::'.$user]; + } else { + $result = null; + try { + $stmt = OC_DB::prepare('SELECT DISTINCT name FROM *PREFIX*categories WHERE userid = ? AND appid = ? ORDER BY name'); + $result = $stmt->execute(array($user, $app)); + } catch(Exception $e) { + OC_Log::write('core','OC_VCategories::ctor, exception: '.$e->getMessage(), OC_Log::ERROR); + OC_Log::write('core','OC_VCategories::ctor, app: '.$app.', user: '.$user, OC_Log::ERROR); + } + if(!is_null($result)) { + while( $row = $result->fetchRow()){ + $this->categories[] = $row['name']; + } + self::$cache[$app.'::'.$user] = $this->categories; + } + } + } + + /** + * @brief Get the categories for a specific. + * @returns array containing the categories as strings. + */ + public function categories() { + return $this->categories; + } + + /** + * @brief Checks whether a category is already saved. + * @param $name The name to check for. + * @returns bool + */ + public function hasCategory($name) { + return ($this->in_arrayi($name, $this->categories) == false ? false : true); + } + + /** + * @brief Add a new category name. + * @param $names A string with a name or an array of strings containing the name(s) of the categor(y|ies) to add. + * @returns bool Returns false on error. + */ + public function add($app, $names) { + $user = OC_User::getUser(); + $newones = array(); + if(!is_array($names)) { + $names = array($names); + } + $names = array_map('trim', $names); + foreach($names as $name) { + if(($this->in_arrayi($name, $this->categories) == false) && $name != '') { + $newones[] = $name; + } + } + if(count($newones) > 0) { + $stmt = OC_DB::prepare( 'INSERT INTO *PREFIX*categories (userid,appid,name) VALUES(?,?,?)' ); + foreach($newones as $name) { + $this->categories[] = $name; + try { + $result = $stmt->execute(array($user, $app, $name)); + } catch(Exception $e) { + OC_Log::write('core','OC_VCategories::add, exception: '.$e->getMessage(), OC_Log::ERROR); + OC_Log::write('core','OC_VCategories::add, app: '.$app.', user: '.$user.', name: '.$name, OC_Log::ERROR); + return false; + } + } + natcasesort($this->categories); // Dunno if this is necessary + } + return true; + } + + /** + * @brief Extracts categories from a vobject and add the ones not already present. + * @param $vobject The instance of OC_VObject to load the categories from. + * @returns bool Returns false if the name already exist (case insensitive) or on error. + */ + public function loadFromVObject($app, $vobject) { + $this->add($vobject->getAsArray('CATEGORIES')); + } + + /** + * @brief Delete a category from the db and from all the vobject supplied + * @param $app + * @param $name + * @param $objects An array of arrays with [id,vobject] (as text) pairs suitable for updating the apps object table. + */ + public function delete($app, $name, array &$objects) { + if(!$this->hasCategory($name)) { + return; + } + try { + $stmt = OC_DB::prepare('DELETE FROM *PREFIX*categories WHERE UPPER(name) = ?'); + $result = $stmt->execute(array(strtoupper($name),)); + } catch(Exception $e) { + OC_Log::write('core','OC_VCategories::delete, exception: '.$e->getMessage(), OC_Log::ERROR); + OC_Log::write('core','OC_VCategories::delete, name: '.$name, OC_Log::ERROR); + return false; + } + unset($this->categories[$this->array_searchi($name, $this->categories)]); + foreach($objects as $key=>&$value) { + $vobject = OC_VObject::parse($value[1]); + if(!is_null($vobject)){ + $categories = $vobject->getAsArray('CATEGORIES'); + $idx = $this->array_searchi($name, $categories); + if($idx) { + unset($categories[$this->array_searchi($name, $categories)]); + $vobject->setString('CATEGORIES', implode(',', $categories)); + $value[1] = $vobject->serialize(); + $objects[$key] = $value; + } + } else { + OC_Log::write('core','OC_VCategories::delete, unable to parse. ID: '.$value[0].', '.substr($value[1], 0, 10).'(...)', OC_Log::DEBUG); + } + } + } + + /** + * @brief Delete all categories for a specific user. Connected to OC_User::post_deleteUser + * @param $parameters The id of the user. + * @returns bool Returns false on error. + */ + public function deleteUser($parameters) { + $user = $parameters['uid']; + try { + $stmt = OC_DB::prepare('DELETE FROM *PREFIX*categories WHERE user = ?'); + $result = $stmt->execute(array($user,)); + } catch(Exception $e) { + OC_Log::write('core','OC_VCategories::deleteFromUser, exception: '.$e->getMessage(), OC_Log::ERROR); + OC_Log::write('core','OC_VCategories::deleteFromUser, user: '.$user, OC_Log::ERROR); + return false; + } + return true; + } + + // case-insensitive in_array + private function in_arrayi($needle, $haystack) { + return in_array(strtolower($needle), array_map('strtolower', $haystack)); + } + + // case-insensitive array_search + private function array_searchi($needle, $haystack) { + return array_search(strtolower($needle),array_map('strtolower',$haystack)); + } +} +?> \ No newline at end of file From 8a1b671fdd902b1ec1b6b6e7f23ef8fe732905ce Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Sun, 19 Feb 2012 17:00:07 +0100 Subject: [PATCH 006/132] Switch from using separate db table to use OC_Preferences. There is a limitation in that the the configvalue field in the preferences table is a varchar(255). --- lib/vcategories.php | 96 ++++++++++++++------------------------------- 1 file changed, 29 insertions(+), 67 deletions(-) diff --git a/lib/vcategories.php b/lib/vcategories.php index 69955d109a..6cc7511e65 100644 --- a/lib/vcategories.php +++ b/lib/vcategories.php @@ -28,47 +28,26 @@ * Category names are not case-sensitive, but will be saved with the case they are * entered in. If a user already has a category 'family' for an app, and tries to add * a category named 'Family' it will be silently ignored. + * NOTE: There is a limitation in that the the configvalue field in the preferences table is a varchar(255). */ -OC_HOOK::connect('OC_User', 'post_deleteUser', 'OC_VCategories', 'deleteUser'); class OC_VCategories { - /** - * cache - */ - protected static $cache = array(); - /** * Categories */ private $categories = array(); + + private $app = ''; /** * @brief Constructor. * @param $app The application identifier e.g. 'contacts' or 'calendar'. */ public function __construct($app, $user=null) { + $this->app = $app; if(is_null($user)) { $user = OC_User::getUser(); } - // Use cache if possible - I doubt this is ever the case. Copy/paste from OC_L10N. - if(array_key_exists($app.'::'.$user, self::$cache)){ - OC_Log::write('core','OC_Categories::ctor, using cache', OC_Log::DEBUG); - $this->categories = self::$cache[$app.'::'.$user]; - } else { - $result = null; - try { - $stmt = OC_DB::prepare('SELECT DISTINCT name FROM *PREFIX*categories WHERE userid = ? AND appid = ? ORDER BY name'); - $result = $stmt->execute(array($user, $app)); - } catch(Exception $e) { - OC_Log::write('core','OC_VCategories::ctor, exception: '.$e->getMessage(), OC_Log::ERROR); - OC_Log::write('core','OC_VCategories::ctor, app: '.$app.', user: '.$user, OC_Log::ERROR); - } - if(!is_null($result)) { - while( $row = $result->fetchRow()){ - $this->categories[] = $row['name']; - } - self::$cache[$app.'::'.$user] = $this->categories; - } - } + $this->categories = OC_VObject::unescapeSemicolons(OC_Preferences::getValue($user, $app, 'extra categories', '')); } /** @@ -93,7 +72,7 @@ class OC_VCategories { * @param $names A string with a name or an array of strings containing the name(s) of the categor(y|ies) to add. * @returns bool Returns false on error. */ - public function add($app, $names) { + public function add($names) { $user = OC_User::getUser(); $newones = array(); if(!is_array($names)) { @@ -106,17 +85,8 @@ class OC_VCategories { } } if(count($newones) > 0) { - $stmt = OC_DB::prepare( 'INSERT INTO *PREFIX*categories (userid,appid,name) VALUES(?,?,?)' ); - foreach($newones as $name) { - $this->categories[] = $name; - try { - $result = $stmt->execute(array($user, $app, $name)); - } catch(Exception $e) { - OC_Log::write('core','OC_VCategories::add, exception: '.$e->getMessage(), OC_Log::ERROR); - OC_Log::write('core','OC_VCategories::add, app: '.$app.', user: '.$user.', name: '.$name, OC_Log::ERROR); - return false; - } - } + $this->categories = $this->cleanArray(array_merge($this->categories, $newones)); + OC_Preferences::setValue(OC_User::getUser(), $this->app, 'extra categories', OC_VObject::escapeSemicolons($this->categories)); natcasesort($this->categories); // Dunno if this is necessary } return true; @@ -127,29 +97,23 @@ class OC_VCategories { * @param $vobject The instance of OC_VObject to load the categories from. * @returns bool Returns false if the name already exist (case insensitive) or on error. */ - public function loadFromVObject($app, $vobject) { + public function loadFromVObject($vobject) { $this->add($vobject->getAsArray('CATEGORIES')); } /** * @brief Delete a category from the db and from all the vobject supplied - * @param $app * @param $name * @param $objects An array of arrays with [id,vobject] (as text) pairs suitable for updating the apps object table. */ - public function delete($app, $name, array &$objects) { + public function delete($name, array &$objects) { + $user = OC_User::getUser(); if(!$this->hasCategory($name)) { return; } - try { - $stmt = OC_DB::prepare('DELETE FROM *PREFIX*categories WHERE UPPER(name) = ?'); - $result = $stmt->execute(array(strtoupper($name),)); - } catch(Exception $e) { - OC_Log::write('core','OC_VCategories::delete, exception: '.$e->getMessage(), OC_Log::ERROR); - OC_Log::write('core','OC_VCategories::delete, name: '.$name, OC_Log::ERROR); - return false; - } unset($this->categories[$this->array_searchi($name, $this->categories)]); + $this->categories = $this->cleanArray($this->categories); + OC_Preferences::setValue($user, $this->app, 'extra categories', OC_VObject::escapeSemicolons($this->categories)); foreach($objects as $key=>&$value) { $vobject = OC_VObject::parse($value[1]); if(!is_null($vobject)){ @@ -167,24 +131,6 @@ class OC_VCategories { } } - /** - * @brief Delete all categories for a specific user. Connected to OC_User::post_deleteUser - * @param $parameters The id of the user. - * @returns bool Returns false on error. - */ - public function deleteUser($parameters) { - $user = $parameters['uid']; - try { - $stmt = OC_DB::prepare('DELETE FROM *PREFIX*categories WHERE user = ?'); - $result = $stmt->execute(array($user,)); - } catch(Exception $e) { - OC_Log::write('core','OC_VCategories::deleteFromUser, exception: '.$e->getMessage(), OC_Log::ERROR); - OC_Log::write('core','OC_VCategories::deleteFromUser, user: '.$user, OC_Log::ERROR); - return false; - } - return true; - } - // case-insensitive in_array private function in_arrayi($needle, $haystack) { return in_array(strtolower($needle), array_map('strtolower', $haystack)); @@ -194,5 +140,21 @@ class OC_VCategories { private function array_searchi($needle, $haystack) { return array_search(strtolower($needle),array_map('strtolower',$haystack)); } + + private function cleanArray($array, $remove_null_number = true){ + $new_array = array(); + $null_exceptions = array(); + + foreach ($array as $key => $value){ + $value = trim($value); + if($remove_null_number){ + $null_exceptions[] = '0'; + } + if(!in_array($value, $null_exceptions) && $value != "") { + $new_array[] = $value; + } + } + return $new_array; + } } ?> \ No newline at end of file From c62673d3601abdefba2ca81ac7d8f8d42fd7f6a5 Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Sun, 19 Feb 2012 23:32:09 +0100 Subject: [PATCH 007/132] Added public static OC_VCategories object to OC_Contacts_App. Parse cards for new categories in add and edit methods. --- apps/contacts/lib/app.php | 2 ++ apps/contacts/lib/vcard.php | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/apps/contacts/lib/app.php b/apps/contacts/lib/app.php index ff348403a9..48298952c1 100644 --- a/apps/contacts/lib/app.php +++ b/apps/contacts/lib/app.php @@ -10,8 +10,10 @@ * This class manages our app actions */ OC_Contacts_App::$l10n = new OC_L10N('contacts'); +OC_Contacts_App::$categories = new OC_VCategories('contacts'); class OC_Contacts_App { public static $l10n; + public static $categories; /** * Render templates/part.details to json output diff --git a/apps/contacts/lib/vcard.php b/apps/contacts/lib/vcard.php index ece203bd45..de95e73255 100644 --- a/apps/contacts/lib/vcard.php +++ b/apps/contacts/lib/vcard.php @@ -114,6 +114,8 @@ class OC_Contacts_VCard{ $card = OC_VObject::parse($data); if(!is_null($card)){ + OC_Contacts_App::$categories->loadFromVObject($card); + $fn = $card->getAsString('FN'); if(!$fn){ // Fix missing 'FN' field. $n = $card->getAsString('N'); @@ -187,6 +189,7 @@ class OC_Contacts_VCard{ $email = null; $card = OC_VObject::parse($data); if(!is_null($card)){ + OC_Contacts_App::$categories->loadFromVObject($card); foreach($card->children as $property){ if($property->name == 'FN'){ $fn = $property->value; @@ -245,6 +248,7 @@ class OC_Contacts_VCard{ $card = OC_VObject::parse($data); if(!is_null($card)){ + OC_Contacts_App::$categories->loadFromVObject($card); foreach($card->children as $property){ if($property->name == 'FN'){ $fn = $property->value; @@ -279,6 +283,7 @@ class OC_Contacts_VCard{ $fn = null; $card = OC_VObject::parse($data); if(!is_null($card)){ + OC_Contacts_App::$categories->loadFromVObject($card); foreach($card->children as $property){ if($property->name == 'FN'){ $fn = $property->value; From 430ccef09cb303e1b2136cd0599f3baddf4acbcd Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Mon, 20 Feb 2012 13:16:51 +0100 Subject: [PATCH 008/132] Added OC_VCategories::rescan() --- lib/vcategories.php | 55 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 45 insertions(+), 10 deletions(-) diff --git a/lib/vcategories.php b/lib/vcategories.php index 6cc7511e65..63ed367230 100644 --- a/lib/vcategories.php +++ b/lib/vcategories.php @@ -36,18 +36,21 @@ class OC_VCategories { */ private $categories = array(); - private $app = ''; + private $app = null; + private $user = null; /** * @brief Constructor. * @param $app The application identifier e.g. 'contacts' or 'calendar'. + * @param $user The user whos data the object will operate on. This parameter should normally be omitted + * but to make an app able to update categories for all users it is made possible to provide it. */ public function __construct($app, $user=null) { $this->app = $app; if(is_null($user)) { - $user = OC_User::getUser(); + $this->user = OC_User::getUser(); } - $this->categories = OC_VObject::unescapeSemicolons(OC_Preferences::getValue($user, $app, 'extra categories', '')); + $this->categories = OC_VObject::unescapeSemicolons(OC_Preferences::getValue($this->user, $app, 'extra categories', '')); } /** @@ -72,8 +75,8 @@ class OC_VCategories { * @param $names A string with a name or an array of strings containing the name(s) of the categor(y|ies) to add. * @returns bool Returns false on error. */ - public function add($names) { - $user = OC_User::getUser(); + public function add($names, $sync=true) { + $user = is_null($this->user) ? OC_User::getUser() : $this->user; $newones = array(); if(!is_array($names)) { $names = array($names); @@ -86,7 +89,9 @@ class OC_VCategories { } if(count($newones) > 0) { $this->categories = $this->cleanArray(array_merge($this->categories, $newones)); - OC_Preferences::setValue(OC_User::getUser(), $this->app, 'extra categories', OC_VObject::escapeSemicolons($this->categories)); + if($sync) { + OC_Preferences::setValue($user, $this->app, 'extra categories', OC_VObject::escapeSemicolons($this->categories)); + } natcasesort($this->categories); // Dunno if this is necessary } return true; @@ -97,8 +102,38 @@ class OC_VCategories { * @param $vobject The instance of OC_VObject to load the categories from. * @returns bool Returns false if the name already exist (case insensitive) or on error. */ - public function loadFromVObject($vobject) { - $this->add($vobject->getAsArray('CATEGORIES')); + public function loadFromVObject($vobject, $sync=true) { + $this->add($vobject->getAsArray('CATEGORIES'), $sync); + } + + /** + * @brief Reset saved categories and rescan supplied vobjects for categories. + * @param $objects An array of vobjects (as text). + * To get the object array, do something like: + * // For Addressbook: + * $categories = new OC_VCategories('contacts'); + * $stmt = OC_DB::prepare( 'SELECT carddata FROM *PREFIX*contacts_cards' ); + * $result = $stmt->execute(); + * $objects = array(); + * if(!is_null($result)) { + * while( $row = $result->fetchRow()){ + * $objects[] = $row['carddata']; + * } + * } + * $categories->rescan($objects); + */ + public function rescan($objects) { + $user = is_null($this->user) ? OC_User::getUser() : $this->user; + $this->categories = array(); + foreach($objects as $object) { + $vobject = OC_VObject::parse($object); + if(!is_null($vobject)){ + $this->loadFromVObject($vobject, false); + } else { + OC_Log::write('core','OC_VCategories::rescan, unable to parse. ID: '.$value[0].', '.substr($value[1], 0, 20).'(...)', OC_Log::DEBUG); + } + } + OC_Preferences::setValue($user, $this->app, 'extra categories', OC_VObject::escapeSemicolons($this->categories)); } /** @@ -107,7 +142,7 @@ class OC_VCategories { * @param $objects An array of arrays with [id,vobject] (as text) pairs suitable for updating the apps object table. */ public function delete($name, array &$objects) { - $user = OC_User::getUser(); + $user = is_null($this->user) ? OC_User::getUser() : $this->user; if(!$this->hasCategory($name)) { return; } @@ -126,7 +161,7 @@ class OC_VCategories { $objects[$key] = $value; } } else { - OC_Log::write('core','OC_VCategories::delete, unable to parse. ID: '.$value[0].', '.substr($value[1], 0, 10).'(...)', OC_Log::DEBUG); + OC_Log::write('core','OC_VCategories::delete, unable to parse. ID: '.$value[0].', '.substr($value[1], 0, 20).'(...)', OC_Log::DEBUG); } } } From 77ab89a7cb1003c88a3035a225ae78e1c5037b5b Mon Sep 17 00:00:00 2001 From: Bart Visscher Date: Mon, 20 Feb 2012 22:32:57 +0100 Subject: [PATCH 009/132] Review changes of OC_VCategory --- lib/vcategories.php | 66 +++++++++++++++++++++++++++------------------ 1 file changed, 40 insertions(+), 26 deletions(-) diff --git a/lib/vcategories.php b/lib/vcategories.php index 63ed367230..8bd03d4423 100644 --- a/lib/vcategories.php +++ b/lib/vcategories.php @@ -4,6 +4,7 @@ * * @author Thomas Tanghus * @copyright 2012 Thomas Tanghus +* @copyright 2012 Bart Visscher bartv@thisnet.nl * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE @@ -23,14 +24,17 @@ /** * Class for easy access to categories in VCARD, VEVENT, VTODO and VJOURNAL. - * A Category can be e.g. 'Family', 'Work', 'Chore', 'Special Occation' or anything else - * that is either parsed from a vobject or that the user chooses to add. - * Category names are not case-sensitive, but will be saved with the case they are - * entered in. If a user already has a category 'family' for an app, and tries to add - * a category named 'Family' it will be silently ignored. - * NOTE: There is a limitation in that the the configvalue field in the preferences table is a varchar(255). + * A Category can be e.g. 'Family', 'Work', 'Chore', 'Special Occation' or + * anything else that is either parsed from a vobject or that the user chooses + * to add. + * Category names are not case-sensitive, but will be saved with the case they + * are entered in. If a user already has a category 'family' for an app, and + * tries to add a category named 'Family' it will be silently ignored. + * NOTE: There is a limitation in that the the configvalue field in the + * preferences table is a varchar(255). */ class OC_VCategories { + const PREF_CATEGORIES_LABEL = 'extra categories'; /** * Categories */ @@ -38,23 +42,24 @@ class OC_VCategories { private $app = null; private $user = null; - + /** * @brief Constructor. * @param $app The application identifier e.g. 'contacts' or 'calendar'. - * @param $user The user whos data the object will operate on. This parameter should normally be omitted - * but to make an app able to update categories for all users it is made possible to provide it. + * @param $user The user whos data the object will operate on. This + * parameter should normally be omitted but to make an app able to + * update categories for all users it is made possible to provide it. */ public function __construct($app, $user=null) { $this->app = $app; if(is_null($user)) { $this->user = OC_User::getUser(); } - $this->categories = OC_VObject::unescapeSemicolons(OC_Preferences::getValue($this->user, $app, 'extra categories', '')); + $this->categories = OC_VObject::unescapeSemicolons(OC_Preferences::getValue($this->user, $app, self::PREF_CATEGORIES_LABEL, '')); } /** - * @brief Get the categories for a specific. + * @brief Get the categories for a specific user. * @returns array containing the categories as strings. */ public function categories() { @@ -67,21 +72,22 @@ class OC_VCategories { * @returns bool */ public function hasCategory($name) { - return ($this->in_arrayi($name, $this->categories) == false ? false : true); + return $this->in_arrayi($name, $this->categories); } /** * @brief Add a new category name. - * @param $names A string with a name or an array of strings containing the name(s) of the categor(y|ies) to add. + * @param $names A string with a name or an array of strings containing + * the name(s) of the categor(y|ies) to add. + * @param $sync bool When true, save the categories * @returns bool Returns false on error. */ public function add($names, $sync=true) { - $user = is_null($this->user) ? OC_User::getUser() : $this->user; - $newones = array(); if(!is_array($names)) { $names = array($names); } $names = array_map('trim', $names); + $newones = array(); foreach($names as $name) { if(($this->in_arrayi($name, $this->categories) == false) && $name != '') { $newones[] = $name; @@ -89,10 +95,10 @@ class OC_VCategories { } if(count($newones) > 0) { $this->categories = $this->cleanArray(array_merge($this->categories, $newones)); - if($sync) { - OC_Preferences::setValue($user, $this->app, 'extra categories', OC_VObject::escapeSemicolons($this->categories)); - } natcasesort($this->categories); // Dunno if this is necessary + if($sync) { + $this->save(); + } } return true; } @@ -100,7 +106,6 @@ class OC_VCategories { /** * @brief Extracts categories from a vobject and add the ones not already present. * @param $vobject The instance of OC_VObject to load the categories from. - * @returns bool Returns false if the name already exist (case insensitive) or on error. */ public function loadFromVObject($vobject, $sync=true) { $this->add($vobject->getAsArray('CATEGORIES'), $sync); @@ -123,17 +128,24 @@ class OC_VCategories { * $categories->rescan($objects); */ public function rescan($objects) { - $user = is_null($this->user) ? OC_User::getUser() : $this->user; $this->categories = array(); foreach($objects as $object) { $vobject = OC_VObject::parse($object); - if(!is_null($vobject)){ + if(!is_null($vobject)) { $this->loadFromVObject($vobject, false); } else { OC_Log::write('core','OC_VCategories::rescan, unable to parse. ID: '.$value[0].', '.substr($value[1], 0, 20).'(...)', OC_Log::DEBUG); } } - OC_Preferences::setValue($user, $this->app, 'extra categories', OC_VObject::escapeSemicolons($this->categories)); + $this->save(); + } + + /** + * @brief Save the list with categories + */ + public function save() { + $escaped_categories = OC_VObject::escapeSemicolons($this->categories); + OC_Preferences::setValue($this->user, $this->app, self::PREF_CATEGORIES_LABEL, $escaped_categories); } /** @@ -142,13 +154,12 @@ class OC_VCategories { * @param $objects An array of arrays with [id,vobject] (as text) pairs suitable for updating the apps object table. */ public function delete($name, array &$objects) { - $user = is_null($this->user) ? OC_User::getUser() : $this->user; if(!$this->hasCategory($name)) { return; } unset($this->categories[$this->array_searchi($name, $this->categories)]); $this->categories = $this->cleanArray($this->categories); - OC_Preferences::setValue($user, $this->app, 'extra categories', OC_VObject::escapeSemicolons($this->categories)); + $this->save(); foreach($objects as $key=>&$value) { $vobject = OC_VObject::parse($value[1]); if(!is_null($vobject)){ @@ -172,10 +183,13 @@ class OC_VCategories { } // case-insensitive array_search - private function array_searchi($needle, $haystack) { + private function array_searchi($needle, $haystack) { return array_search(strtolower($needle),array_map('strtolower',$haystack)); } + /* + * this is for a bug in the code, need to check if it is still needed + */ private function cleanArray($array, $remove_null_number = true){ $new_array = array(); $null_exceptions = array(); @@ -192,4 +206,4 @@ class OC_VCategories { return $new_array; } } -?> \ No newline at end of file +?> From 7c7031df44bd78bf8253d44a801b8bf25490f4bb Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Tue, 21 Feb 2012 00:02:27 +0100 Subject: [PATCH 010/132] Forgot to assign param. --- lib/vcategories.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/vcategories.php b/lib/vcategories.php index 8bd03d4423..f9e4d1b348 100644 --- a/lib/vcategories.php +++ b/lib/vcategories.php @@ -52,9 +52,7 @@ class OC_VCategories { */ public function __construct($app, $user=null) { $this->app = $app; - if(is_null($user)) { - $this->user = OC_User::getUser(); - } + $this->user = is_null($user) ? OC_User::getUser() : $user; $this->categories = OC_VObject::unescapeSemicolons(OC_Preferences::getValue($this->user, $app, self::PREF_CATEGORIES_LABEL, '')); } From be948a9baad3eda5821f1dfaebefc8271454872b Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Tue, 21 Feb 2012 09:53:03 +0100 Subject: [PATCH 011/132] Check for empty value in ctor and being conservative about configvalue name ;-) --- lib/vcategories.php | 26 ++++---------------------- 1 file changed, 4 insertions(+), 22 deletions(-) diff --git a/lib/vcategories.php b/lib/vcategories.php index f9e4d1b348..250aa608c1 100644 --- a/lib/vcategories.php +++ b/lib/vcategories.php @@ -34,7 +34,7 @@ * preferences table is a varchar(255). */ class OC_VCategories { - const PREF_CATEGORIES_LABEL = 'extra categories'; + const PREF_CATEGORIES_LABEL = 'extra_categories'; /** * Categories */ @@ -53,7 +53,8 @@ class OC_VCategories { public function __construct($app, $user=null) { $this->app = $app; $this->user = is_null($user) ? OC_User::getUser() : $user; - $this->categories = OC_VObject::unescapeSemicolons(OC_Preferences::getValue($this->user, $app, self::PREF_CATEGORIES_LABEL, '')); + $categories = trim(OC_Preferences::getValue($this->user, $app, self::PREF_CATEGORIES_LABEL, '')); + $this->categories = $categories != '' ? OC_VObject::unescapeSemicolons($categories) : array(); } /** @@ -92,7 +93,7 @@ class OC_VCategories { } } if(count($newones) > 0) { - $this->categories = $this->cleanArray(array_merge($this->categories, $newones)); + $this->categories = array_merge($this->categories, $newones); natcasesort($this->categories); // Dunno if this is necessary if($sync) { $this->save(); @@ -156,7 +157,6 @@ class OC_VCategories { return; } unset($this->categories[$this->array_searchi($name, $this->categories)]); - $this->categories = $this->cleanArray($this->categories); $this->save(); foreach($objects as $key=>&$value) { $vobject = OC_VObject::parse($value[1]); @@ -185,23 +185,5 @@ class OC_VCategories { return array_search(strtolower($needle),array_map('strtolower',$haystack)); } - /* - * this is for a bug in the code, need to check if it is still needed - */ - private function cleanArray($array, $remove_null_number = true){ - $new_array = array(); - $null_exceptions = array(); - - foreach ($array as $key => $value){ - $value = trim($value); - if($remove_null_number){ - $null_exceptions[] = '0'; - } - if(!in_array($value, $null_exceptions) && $value != "") { - $new_array[] = $value; - } - } - return $new_array; - } } ?> From faf6055baa224fbf4248a70d28ae4416c9c7eb1c Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Wed, 22 Feb 2012 14:19:23 +0100 Subject: [PATCH 012/132] Translate and fix copy/paste error. --- apps/contacts/ajax/loadphoto.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/apps/contacts/ajax/loadphoto.php b/apps/contacts/ajax/loadphoto.php index 358e046942..1f4cde0b53 100644 --- a/apps/contacts/ajax/loadphoto.php +++ b/apps/contacts/ajax/loadphoto.php @@ -18,8 +18,6 @@ * You should have received a copy of the GNU Affero General Public * License along with this library. If not, see . * - * TODO: Translatable strings. - * Remember to delete tmp file at some point. */ // Init owncloud require_once('../../../lib/base.php'); @@ -33,7 +31,7 @@ OC_JSON::checkAppEnabled('contacts'); function bailOut($msg) { OC_JSON::error(array('data' => array('message' => $msg))); - OC_Log::write('contacts','ajax/savecrop.php: '.$msg, OC_Log::DEBUG); + OC_Log::write('contacts','ajax/loadphoto.php: '.$msg, OC_Log::DEBUG); exit(); } @@ -42,7 +40,7 @@ $image = null; $id = isset($_GET['id']) ? $_GET['id'] : ''; if($id == '') { - bailOut('Missing contact id.'); + bailOut(OC_Contacts_App::$l10n->t('Missing contact id.')); } $tmpl = new OC_TEMPLATE("contacts", "part.contactphoto"); From 1794ad353d90d8168ae592a192353f1375473462 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Sat, 3 Mar 2012 00:55:17 +0100 Subject: [PATCH 013/132] fix file_get_content on empty files for filestorage common --- lib/filestorage/common.php | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/filestorage/common.php b/lib/filestorage/common.php index fa0e7babf5..ed12e67eeb 100644 --- a/lib/filestorage/common.php +++ b/lib/filestorage/common.php @@ -59,7 +59,14 @@ abstract class OC_Filestorage_Common extends OC_Filestorage { } public function file_get_contents($path) { $handle = $this->fopen($path, "r"); - return fread($handle, $this->filesize($path)); + if(!$handle){ + return false; + } + $size=$this->filesize($path); + if($size==0){ + return ''; + } + return fread($handle, $size); } public function file_put_contents($path,$data) { $handle = $this->fopen($path, "w"); From c609b3084166c08249a68796d0a2d5941ac0c8e7 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Sat, 3 Mar 2012 00:55:47 +0100 Subject: [PATCH 014/132] fix the filestorage test a bit --- tests/lib/filestorage.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/lib/filestorage.php b/tests/lib/filestorage.php index f8d4d9c439..9ffa0eca9c 100644 --- a/tests/lib/filestorage.php +++ b/tests/lib/filestorage.php @@ -137,7 +137,8 @@ abstract class Test_FileStorage extends UnitTestCase { $mTime=$this->instance->filemtime('/lorem.txt'); $this->assertTrue($ctimeStart<=$cTime); $this->assertTrue($cTime<=$ctimeEnd); - $this->assertEqual($cTime,$mTime); + $this->assertTrue($ctimeStart<=$mTime); + $this->assertTrue($mTime<=$ctimeEnd); $this->assertEqual(filesize($textFile),$this->instance->filesize('/lorem.txt')); $stat=$this->instance->stat('/lorem.txt'); From 042878a5a90d95ed49fcbdba4ea710ea545b61cc Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Sat, 3 Mar 2012 00:57:03 +0100 Subject: [PATCH 015/132] add archive library and a storage provider on top of the archive library only zip backend is implemented atm --- apps/files_archive/appinfo/app.php | 14 +++ apps/files_archive/appinfo/info.xml | 10 ++ apps/files_archive/lib/archive.php | 99 +++++++++++++++ apps/files_archive/lib/storage.php | 102 +++++++++++++++ apps/files_archive/lib/zip.php | 182 +++++++++++++++++++++++++++ apps/files_archive/tests/archive.php | 97 ++++++++++++++ apps/files_archive/tests/storage.php | 19 +++ apps/files_archive/tests/zip.php | 20 +++ 8 files changed, 543 insertions(+) create mode 100644 apps/files_archive/appinfo/app.php create mode 100644 apps/files_archive/appinfo/info.xml create mode 100644 apps/files_archive/lib/archive.php create mode 100644 apps/files_archive/lib/storage.php create mode 100644 apps/files_archive/lib/zip.php create mode 100644 apps/files_archive/tests/archive.php create mode 100644 apps/files_archive/tests/storage.php create mode 100644 apps/files_archive/tests/zip.php diff --git a/apps/files_archive/appinfo/app.php b/apps/files_archive/appinfo/app.php new file mode 100644 index 0000000000..e75f6fa055 --- /dev/null +++ b/apps/files_archive/appinfo/app.php @@ -0,0 +1,14 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +OC::$CLASSPATH['OC_Archive'] = 'apps/files_archive/lib/archive.php'; +foreach(array('ZIP') as $type){ + OC::$CLASSPATH['OC_Archive_'.$type] = 'apps/files_archive/lib/'.strtolower($type).'.php'; +} + +OC::$CLASSPATH['OC_Filestorage_Archive']='apps/files_archive/lib/storage.php'; diff --git a/apps/files_archive/appinfo/info.xml b/apps/files_archive/appinfo/info.xml new file mode 100644 index 0000000000..df767d39f6 --- /dev/null +++ b/apps/files_archive/appinfo/info.xml @@ -0,0 +1,10 @@ + + + files_archive + Archive support + Transparent opening of archives + 0.1 + AGPL + Robin Appelman + 3 + diff --git a/apps/files_archive/lib/archive.php b/apps/files_archive/lib/archive.php new file mode 100644 index 0000000000..be89f894fb --- /dev/null +++ b/apps/files_archive/lib/archive.php @@ -0,0 +1,99 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +abstract class OC_Archive{ + /** + * open any of the supporeted archive types + * @param string path + * @return OC_Archive + */ + public static function open($path){ + $ext=substr($path,strrpos($path,'.')); + switch($ext){ + case '.zip': + return new OC_Archive_ZIP($path); + } + } + + abstract function __construct($source); + /** + * add an empty folder to the archive + * @param string path + * @return bool + */ + abstract function addFolder($path); + /** + * add a file to the archive + * @param string path + * @param string source either a local file or string data + * @return bool + */ + abstract function addFile($path,$source=''); + /** + * rename a file or folder in the archive + * @param string source + * @param string dest + * @return bool + */ + abstract function rename($source,$dest); + /** + * get the uncompressed size of a file in the archive + * @param string path + * @return int + */ + abstract function filesize($path); + /** + * get the last modified time of a file in the archive + * @param string path + * @return int + */ + abstract function mtime($path); + /** + * get the files in a folder + * @param path + * @return array + */ + abstract function getFolder($path); + /** + *get all files in the archive + * @return array + */ + abstract function getFiles(); + /** + * get the content of a file + * @param string path + * @return string + */ + abstract function getFile($path); + /** + * extract a single file from the archive + * @param string path + * @param string dest + * @return bool + */ + abstract function extractFile($path,$dest); + /** + * check if a file or folder exists in the archive + * @param string path + * @return bool + */ + abstract function fileExists($path); + /** + * remove a file or folder from the archive + * @param string path + * @return bool + */ + abstract function remove($path); + /** + * get a file handler + * @param string path + * @param string mode + * @return resource + */ + abstract function getStream($path,$mode); +} diff --git a/apps/files_archive/lib/storage.php b/apps/files_archive/lib/storage.php new file mode 100644 index 0000000000..4f4c0ef2ab --- /dev/null +++ b/apps/files_archive/lib/storage.php @@ -0,0 +1,102 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +class OC_Filestorage_Archive extends OC_Filestorage_Common{ + /** + * underlying local storage used for missing functions + * @var OC_Archive + */ + private $archive; + private $path; + + private function stripPath($path){//files should never start with / + if(substr($path,0,1)=='/'){ + return substr($path,1); + } + return $path; + } + + public function __construct($params){ + $this->archive=OC_Archive::open($params['archive']); + $this->path=$params['archive']; + } + + public function mkdir($path){ + $path=$this->stripPath($path); + return $this->archive->addFolder($path); + } + public function rmdir($path){ + $path=$this->stripPath($path); + return $this->archive->remove($path.'/'); + } + public function opendir($path){ + $path=$this->stripPath($path); + $content=$this->archive->getFolder($path); + foreach($content as &$file){ + if(substr($file,-1)=='/'){ + $file=substr($file,0,-1); + } + } + $id=md5($this->path.$path); + OC_FakeDirStream::$dirs[$id]=$content; + return opendir('fakedir://'.$id); + } + public function stat($path){ + $ctime=filectime($this->path); + $path=$this->stripPath($path); + if($path==''){ + $stat=stat($this->path); + }else{ + $stat=array(); + $stat['mtime']=$this->archive->mtime($path); + $stat['size']=$this->archive->filesize($path); + } + $stat['ctime']=$ctime; + return $stat; + } + public function filetype($path){ + $path=$this->stripPath($path); + if($path==''){ + return 'dir'; + } + return $this->archive->fileExists($path.'/')?'dir':'file'; + } + public function is_readable($path){ + return is_readable($this->path); + } + public function is_writable($path){ + return is_writable($this->path); + } + public function file_exists($path){ + $path=$this->stripPath($path); + if($path==''){ + return file_exists($this->path); + } + return $this->archive->fileExists($path) or $this->archive->fileExists($path.'/'); + } + public function unlink($path){ + $path=$this->stripPath($path); + return $this->archive->remove($path); + } + public function fopen($path,$mode){ + $path=$this->stripPath($path); + return $this->archive->getStream($path,$mode); + } + public function free_space($path){ + return 0; + } + public function touch($path, $mtime=null){ + if(is_null($mtime)){ + $tmpFile=OC_Helper::tmpFile(); + $this->archive->extractFile($path,$tmpFile); + $this->archive->addfile($path,$tmpFile); + }else{ + return false;//not supported + } + } +} diff --git a/apps/files_archive/lib/zip.php b/apps/files_archive/lib/zip.php new file mode 100644 index 0000000000..eab101b3a5 --- /dev/null +++ b/apps/files_archive/lib/zip.php @@ -0,0 +1,182 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +class OC_Archive_ZIP extends OC_Archive{ + /** + * @var ZipArchive zip + */ + private $zip=null; + private $contents=array(); + private $success=false; + private $path; + + function __construct($source){ + $this->path=$source; + $this->zip=new ZipArchive(); + if($this->zip->open($source,ZipArchive::CREATE)){ + }else{ + OC_LOG::write('files_archive','Error while opening archive '.$source,OC_Log::WARN); + } + } + /** + * add an empty folder to the archive + * @param string path + * @return bool + */ + function addFolder($path){ + return $this->zip->addEmptyDir($path); + } + /** + * add a file to the archive + * @param string path + * @param string source either a local file or string data + * @return bool + */ + function addFile($path,$source=''){ + if(file_exists($source)){ + $result=$this->zip->addFile($source,$path); + }else{ + $result=$this->zip->addFromString($path,$source); + } + if($result){ + $this->zip->close();//close and reopen to save the zip + $this->zip->open($this->path); + } + return $result; + } + /** + * rename a file or folder in the archive + * @param string source + * @param string dest + * @return bool + */ + function rename($source,$dest){ + return $this->zip->renameName($source,$dest); + } + /** + * get the uncompressed size of a file in the archive + * @param string path + * @return int + */ + function filesize($path){ + $stat=$this->zip->statName($path); + return $stat['size']; + } + /** + * get the last modified time of a file in the archive + * @param string path + * @return int + */ + function mtime($path){ + $stat=$this->zip->statName($path); + return $stat['mtime']; + } + /** + * get the files in a folder + * @param path + * @return array + */ + function getFolder($path){ + $files=$this->getFiles(); + $folderContent=array(); + $pathLength=strlen($path); + foreach($files as $file){ + if(substr($file,0,$pathLength)==$path and $file!=$path){ + if(strrpos(substr($file,0,-1),'/')<=$pathLength){ + $folderContent[]=substr($file,$pathLength); + } + } + } + return $folderContent; + } + /** + *get all files in the archive + * @return array + */ + function getFiles(){ + if(count($this->contents)){ + return $this->contents; + } + $fileCount=$this->zip->numFiles; + $files=array(); + for($i=0;$i<$fileCount;$i++){ + $files[]=$this->zip->getNameIndex($i); + } + $this->contents=$files; + return $files; + } + /** + * get the content of a file + * @param string path + * @return string + */ + function getFile($path){ + return $this->zip->getFromName($path); + } + /** + * extract a single file from the archive + * @param string path + * @param string dest + * @return bool + */ + function extractFile($path,$dest){ + $fp = $this->zip->getStream($path); + file_put_contents($dest,$fp); + } + /** + * check if a file or folder exists in the archive + * @param string path + * @return bool + */ + function fileExists($path){ + return $this->zip->locateName($path)!==false; + } + /** + * remove a file or folder from the archive + * @param string path + * @return bool + */ + function remove($path){ + return $this->zip->deleteName($path); + } + /** + * get a file handler + * @param string path + * @param string mode + * @return resource + */ + function getStream($path,$mode){ + if($mode=='r' or $mode=='rb'){ + return $this->zip->getStream($path); + }else{//since we cant directly get a writable stream, make a temp copy of the file and put it back in the archive when the stream is closed + if(strrpos($path,'.')!==false){ + $ext=substr($path,strrpos($path,'.')); + }else{ + $ext=''; + } + $tmpFile=OC_Helper::tmpFile($ext); + OC_CloseStreamWrapper::$callBacks[$tmpFile]=array($this,'writeBack'); + if($this->fileExists($path)){ + $this->extractFile($path,$tmpFile); + } + self::$tempFiles[$tmpFile]=$path; + return fopen('close://'.$tmpFile,$mode); + } + } + + private static $tempFiles=array(); + /** + * write back temporary files + */ + function writeBack($tmpFile){ + if(isset(self::$tempFiles[$tmpFile])){ + $this->addFile(self::$tempFiles[$tmpFile],$tmpFile); + unlink($tmpFile); + } + } +} diff --git a/apps/files_archive/tests/archive.php b/apps/files_archive/tests/archive.php new file mode 100644 index 0000000000..2e26b5e03b --- /dev/null +++ b/apps/files_archive/tests/archive.php @@ -0,0 +1,97 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +abstract class Test_Archive extends UnitTestCase { + /** + * @var OC_Archive + */ + protected $instance; + + /** + * get the existing test archive + * @return OC_Archive + */ + abstract protected function getExisting(); + /** + * get a new archive for write testing + * @return OC_Archive + */ + abstract protected function getNew(); + + public function testGetFiles(){ + $this->instance=$this->getExisting(); + $allFiles=$this->instance->getFiles(); + $expected=array('lorem.txt','logo-wide.png','dir/','dir/lorem.txt'); + $this->assertEqual(4,count($allFiles)); + foreach($expected as $file){ + $this->assertNotIdentical(false,array_search($file,$allFiles),'cant find '.$file.' in archive'); + $this->assertTrue($this->instance->fileExists($file)); + } + $this->assertFalse($this->instance->fileExists('non/existing/file')); + + $rootContent=$this->instance->getFolder(''); + $expected=array('lorem.txt','logo-wide.png','dir/'); + $this->assertEqual(3,count($rootContent)); + foreach($expected as $file){ + $this->assertNotIdentical(false,array_search($file,$rootContent),'cant find '.$file.' in archive'); + } + + $dirContent=$this->instance->getFolder('dir/'); + $expected=array('lorem.txt'); + $this->assertEqual(1,count($dirContent)); + foreach($expected as $file){ + $this->assertNotIdentical(false,array_search($file,$dirContent),'cant find '.$file.' in archive'); + } + } + + public function testContent(){ + $this->instance=$this->getExisting(); + $dir=OC::$SERVERROOT.'/apps/files_archive/tests/data'; + $textFile=$dir.'/lorem.txt'; + $this->assertEqual(file_get_contents($textFile),$this->instance->getFile('lorem.txt')); + + $tmpFile=OC_Helper::tmpFile('.txt'); + $this->instance->extractFile('lorem.txt',$tmpFile); + $this->assertEqual(file_get_contents($textFile),file_get_contents($tmpFile)); + } + + public function testWrite(){ + $dir=OC::$SERVERROOT.'/apps/files_archive/tests/data'; + $textFile=$dir.'/lorem.txt'; + $this->instance=$this->getNew(); + $this->assertEqual(0,count($this->instance->getFiles())); + $this->instance->addFile('lorem.txt',$textFile); + $this->assertEqual(1,count($this->instance->getFiles())); + $this->assertTrue($this->instance->fileExists('lorem.txt')); + + $this->assertEqual(file_get_contents($textFile),$this->instance->getFile('lorem.txt')); + $this->instance->addFile('lorem.txt','foobar'); + $this->assertEqual('foobar',$this->instance->getFile('lorem.txt')); + } + + public function testReadStream(){ + $dir=OC::$SERVERROOT.'/apps/files_archive/tests/data'; + $this->instance=$this->getExisting(); + $fh=$this->instance->getStream('lorem.txt','r'); + $this->assertTrue($fh); + $content=fread($fh,$this->instance->filesize('lorem.txt')); + fclose($fh); + $this->assertEqual(file_get_contents($dir.'/lorem.txt'),$content); + } + public function testWriteStream(){ + $dir=OC::$SERVERROOT.'/apps/files_archive/tests/data'; + $this->instance=$this->getNew(); + $fh=$this->instance->getStream('lorem.txt','w'); + $source=fopen($dir.'/lorem.txt','r'); + OC_Helper::streamCopy($source,$fh); + fclose($source); + fclose($fh); + $this->assertTrue($this->instance->fileExists('lorem.txt')); + $this->assertEqual(file_get_contents($dir.'/lorem.txt'),$this->instance->getFile('lorem.txt')); + } +} diff --git a/apps/files_archive/tests/storage.php b/apps/files_archive/tests/storage.php new file mode 100644 index 0000000000..1dfaca2ce5 --- /dev/null +++ b/apps/files_archive/tests/storage.php @@ -0,0 +1,19 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +class Test_Filestorage_Archive_Zip extends Test_FileStorage { + /** + * @var string tmpDir + */ + public function setUp(){ + $tmpFile=OC_Helper::tmpFile('.zip'); + $this->instance=new OC_Filestorage_Archive(array('archive'=>$tmpFile)); + } +} + +?> \ No newline at end of file diff --git a/apps/files_archive/tests/zip.php b/apps/files_archive/tests/zip.php new file mode 100644 index 0000000000..3ff713eda7 --- /dev/null +++ b/apps/files_archive/tests/zip.php @@ -0,0 +1,20 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +require_once('archive.php'); + +class Test_Archive_ZIP extends Test_Archive{ + protected function getExisting(){ + $dir=OC::$SERVERROOT.'/apps/files_archive/tests/data'; + return new OC_Archive_ZIP($dir.'/data.zip'); + } + + protected function getNew(){ + return new OC_Archive_ZIP(OC_Helper::tmpFile('.zip')); + } +} From 23b64cd9cee55b6b17fa8dec44d1cb8d06e88af8 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Sat, 3 Mar 2012 01:37:00 +0100 Subject: [PATCH 016/132] remove the archive after a testcase is done --- apps/files_archive/tests/storage.php | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/apps/files_archive/tests/storage.php b/apps/files_archive/tests/storage.php index 1dfaca2ce5..4d0a83356b 100644 --- a/apps/files_archive/tests/storage.php +++ b/apps/files_archive/tests/storage.php @@ -10,9 +10,15 @@ class Test_Filestorage_Archive_Zip extends Test_FileStorage { /** * @var string tmpDir */ + private $tmpFile; + public function setUp(){ - $tmpFile=OC_Helper::tmpFile('.zip'); - $this->instance=new OC_Filestorage_Archive(array('archive'=>$tmpFile)); + $this->tmpFile=OC_Helper::tmpFile('.zip'); + $this->instance=new OC_Filestorage_Archive(array('archive'=>$this->tmpFile)); + } + + public function tearDown(){ + unlink($this->tmpFile); } } From 4c45483ad3acd5b675e54893686f912a32f10a12 Mon Sep 17 00:00:00 2001 From: Georg Ehrke Date: Sat, 3 Mar 2012 14:30:52 +0100 Subject: [PATCH 017/132] make calendar compatible with php 5.2 - works for me with PHP 5.2.12 --- apps/calendar/ajax/events.php | 9 +++++-- apps/calendar/appinfo/app.php | 46 +++++++++++++++++------------------ 2 files changed, 29 insertions(+), 26 deletions(-) diff --git a/apps/calendar/ajax/events.php b/apps/calendar/ajax/events.php index a912889f29..922df90b76 100755 --- a/apps/calendar/ajax/events.php +++ b/apps/calendar/ajax/events.php @@ -27,8 +27,13 @@ function create_return_event($event, $vevent){ OC_JSON::checkLoggedIn(); OC_JSON::checkAppEnabled('calendar'); -$start = DateTime::createFromFormat('U', $_GET['start']); -$end = DateTime::createFromFormat('U', $_GET['end']); +if(version_compare(PHP_VERSION, '5.3.0', '>=')){ + $start = DateTime::createFromFormat('U', $_GET['start']); + $end = DateTime::createFromFormat('U', $_GET['end']); +}else{ + $start = new DateTime('@' . $_GET['start']); + $end = new DateTime('@' . $_GET['end']); +} $calendar_id = $_GET['calendar_id']; if (is_numeric($calendar_id)) { diff --git a/apps/calendar/appinfo/app.php b/apps/calendar/appinfo/app.php index 0968737219..f297c4d16d 100644 --- a/apps/calendar/appinfo/app.php +++ b/apps/calendar/appinfo/app.php @@ -1,25 +1,23 @@ =')){ - $l=new OC_L10N('calendar'); - OC::$CLASSPATH['OC_Calendar_App'] = 'apps/calendar/lib/app.php'; - OC::$CLASSPATH['OC_Calendar_Calendar'] = 'apps/calendar/lib/calendar.php'; - OC::$CLASSPATH['OC_Calendar_Object'] = 'apps/calendar/lib/object.php'; - OC::$CLASSPATH['OC_Calendar_Hooks'] = 'apps/calendar/lib/hooks.php'; - OC::$CLASSPATH['OC_Connector_Sabre_CalDAV'] = 'apps/calendar/lib/connector_sabre.php'; - OC::$CLASSPATH['OC_Search_Provider_Calendar'] = 'apps/calendar/lib/search.php'; - OC_HOOK::connect('OC_User', 'post_deleteUser', 'OC_Calendar_Hooks', 'deleteUser'); - OC_Hook::connect('OC_DAV', 'initialize', 'OC_Calendar_Hooks', 'initializeCalDAV'); - OC_Util::addScript('calendar','loader'); - OC_App::register( array( - 'order' => 10, - 'id' => 'calendar', - 'name' => 'Calendar' )); - OC_App::addNavigationEntry( array( - 'id' => 'calendar_index', - 'order' => 10, - 'href' => OC_Helper::linkTo( 'calendar', 'index.php' ), - 'icon' => OC_Helper::imagePath( 'calendar', 'icon.svg' ), - 'name' => $l->t('Calendar'))); - OC_App::registerPersonal('calendar', 'settings'); - OC_Search::registerProvider('OC_Search_Provider_Calendar'); -} +$l=new OC_L10N('calendar'); +OC::$CLASSPATH['OC_Calendar_App'] = 'apps/calendar/lib/app.php'; +OC::$CLASSPATH['OC_Calendar_Calendar'] = 'apps/calendar/lib/calendar.php'; +OC::$CLASSPATH['OC_Calendar_Object'] = 'apps/calendar/lib/object.php'; +OC::$CLASSPATH['OC_Calendar_Hooks'] = 'apps/calendar/lib/hooks.php'; +OC::$CLASSPATH['OC_Connector_Sabre_CalDAV'] = 'apps/calendar/lib/connector_sabre.php'; +OC::$CLASSPATH['OC_Search_Provider_Calendar'] = 'apps/calendar/lib/search.php'; +OC_HOOK::connect('OC_User', 'post_deleteUser', 'OC_Calendar_Hooks', 'deleteUser'); +OC_Hook::connect('OC_DAV', 'initialize', 'OC_Calendar_Hooks', 'initializeCalDAV'); +OC_Util::addScript('calendar','loader'); +OC_App::register( array( + 'order' => 10, + 'id' => 'calendar', + 'name' => 'Calendar' )); +OC_App::addNavigationEntry( array( + 'id' => 'calendar_index', + 'order' => 10, + 'href' => OC_Helper::linkTo( 'calendar', 'index.php' ), + 'icon' => OC_Helper::imagePath( 'calendar', 'icon.svg' ), + 'name' => $l->t('Calendar'))); +OC_App::registerPersonal('calendar', 'settings'); +OC_Search::registerProvider('OC_Search_Provider_Calendar'); \ No newline at end of file From 2e365658c856e1dffd1ee748db40158fdda0edc3 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Sat, 3 Mar 2012 18:02:07 +0100 Subject: [PATCH 018/132] better handeling of files that can behave like folder (e.g. archives) --- files/index.php | 2 +- lib/filecache.php | 7 ++++--- lib/filestorage/local.php | 2 +- lib/filesystem.php | 10 ++++------ lib/filesystemview.php | 1 + 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/files/index.php b/files/index.php index a29d3fb7e1..79261e495b 100644 --- a/files/index.php +++ b/files/index.php @@ -40,7 +40,7 @@ OC_App::setActiveNavigationEntry( "files_index" ); // Load the files $dir = isset( $_GET['dir'] ) ? stripslashes($_GET['dir']) : ''; // Redirect if directory does not exist -if(!OC_Filesystem::is_dir($dir)) { +if(!OC_Filesystem::is_dir($dir.'/')) { header("Location: ".$_SERVER['PHP_SELF'].""); } diff --git a/lib/filecache.php b/lib/filecache.php index 732160c216..e94ae49c73 100644 --- a/lib/filecache.php +++ b/lib/filecache.php @@ -323,10 +323,11 @@ class OC_FileCache{ $path=$params['path']; $fullPath=$view->getRoot().$path; $mimetype=$view->getMimeType($path); + $dir=$view->is_dir($path.'/'); //dont use self::get here, we don't want inifinte loops when a file has changed $cachedSize=self::getCachedSize($path,$root); $size=0; - if($mimetype=='httpd/unix-directory'){ + if($dir){ if(self::inCache($path,$root)){ $parent=self::getFileId($fullPath); $query=OC_DB::prepare('SELECT size FROM *PREFIX*fscache WHERE parent=?'); @@ -465,13 +466,13 @@ class OC_FileCache{ $view=new OC_FilesystemView(($root=='/')?'':$root); } self::scanFile($path,$root); - $dh=$view->opendir($path); + $dh=$view->opendir($path.'/'); $totalSize=0; if($dh){ while (($filename = readdir($dh)) !== false) { if($filename != '.' and $filename != '..'){ $file=$path.'/'.$filename; - if($view->is_dir($file)){ + if($view->is_dir($file.'/')){ if($eventSource){ $eventSource->send('scanning',array('file'=>$file,'count'=>$count)); } diff --git a/lib/filestorage/local.php b/lib/filestorage/local.php index 8e07ce6025..750a1fb36d 100644 --- a/lib/filestorage/local.php +++ b/lib/filestorage/local.php @@ -21,7 +21,7 @@ class OC_Filestorage_Local extends OC_Filestorage{ return opendir($this->datadir.$path); } public function is_dir($path){ - return (is_dir($this->datadir.$path) or substr($path,-1)=='/'); + return @is_dir($this->datadir.$path); } public function is_file($path){ return is_file($this->datadir.$path); diff --git a/lib/filesystem.php b/lib/filesystem.php index 5013b3968c..12905d189f 100644 --- a/lib/filesystem.php +++ b/lib/filesystem.php @@ -146,20 +146,15 @@ class OC_Filesystem{ * @return string */ static public function getMountPoint($path){ + OC_Hook::emit(self::CLASSNAME,'get_mountpoint',array('path'=>$path)); if(!$path){ $path='/'; } if(substr($path,0,1)!=='/'){ $path='/'.$path; } - if(substr($path,-1)!=='/'){ - $path=$path.'/'; - } $foundMountPoint=''; foreach(OC_Filesystem::$mounts as $mountpoint=>$storage){ - if(substr($mountpoint,-1)!=='/'){ - $mountpoint=$mountpoint.'/'; - } if($mountpoint==$path){ return $mountpoint; } @@ -259,6 +254,9 @@ class OC_Filesystem{ * @param string mountpoint */ static public function mount($class,$arguments,$mountpoint){ + if(substr($mountpoint,-1)!=='/'){ + $mountpoint=$mountpoint.'/'; + } if(substr($mountpoint,0,1)!=='/'){ $mountpoint='/'.$mountpoint; } diff --git a/lib/filesystemview.php b/lib/filesystemview.php index 2d54a676c8..89e0385fe9 100644 --- a/lib/filesystemview.php +++ b/lib/filesystemview.php @@ -205,6 +205,7 @@ class OC_FilesystemView { $count=OC_Helper::streamCopy($data,$target); $storage1=$this->getStorage($path1); $storage1->unlink($this->getInternalPath($path1)); + $result=$count>0; } OC_Hook::emit( OC_Filesystem::CLASSNAME, OC_Filesystem::signal_post_rename, array( OC_Filesystem::signal_param_oldpath => $path1, OC_Filesystem::signal_param_newpath=>$path2)); return $result; From 0f540843058b869829a48f8d41abfff19b0862d4 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Sat, 3 Mar 2012 18:23:53 +0100 Subject: [PATCH 019/132] also delete childs of folders from the cache --- lib/filecache.php | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/lib/filecache.php b/lib/filecache.php index e94ae49c73..be2a00a19a 100644 --- a/lib/filecache.php +++ b/lib/filecache.php @@ -168,19 +168,28 @@ class OC_FileCache{ /** * delete info from the cache - * @param string $path + * @param string/int $file * @param string root (optional) */ - public static function delete($path,$root=''){ - if(!$root){ - $root=OC_Filesystem::getRoot(); + public static function delete($file,$root=''){ + if(!is_numeric($file)){ + if(!$root){ + $root=OC_Filesystem::getRoot(); + } + if($root=='/'){ + $root=''; + } + $path=$root.$file; + self::delete(self::getFileId($path)); + }elseif($file!=-1){ + $query=OC_DB::prepare('SELECT id FROM *PREFIX*fscache WHERE parent=?'); + $query->execute(array($file)); + while($child=$query->fetchRow()){ + self::delete(intval($child['id'])); + } + $query=OC_DB::prepare('DELETE FROM *PREFIX*fscache WHERE id=?'); + $query->execute(array($file)); } - if($root=='/'){ - $root=''; - } - $path=$root.$path; - $query=OC_DB::prepare('DELETE FROM *PREFIX*fscache WHERE path=?'); - $query->execute(array($path)); } /** From bb97cbbb0c7a58513e28d363c03ede4918034f21 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Sat, 3 Mar 2012 18:24:10 +0100 Subject: [PATCH 020/132] fix commong filestorage for files without extention --- lib/filestorage/common.php | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/lib/filestorage/common.php b/lib/filestorage/common.php index ed12e67eeb..f632474df0 100644 --- a/lib/filestorage/common.php +++ b/lib/filestorage/common.php @@ -99,7 +99,11 @@ abstract class OC_Filestorage_Common extends OC_Filestorage { return false; } $head=fread($source,8192);//8kb should suffice to determine a mimetype - $extention=substr($path,strrpos($path,'.')); + if($pos=strrpos($path,'.')){ + $extention=substr($path,$pos); + }else{ + $extention=''; + } $tmpFile=OC_Helper::tmpFile($extention); file_put_contents($tmpFile,$head); $mime=OC_Helper::getMimeType($tmpFile); @@ -124,7 +128,11 @@ abstract class OC_Filestorage_Common extends OC_Filestorage { if(!$source){ return false; } - $extention=substr($path,strrpos($path,'.')); + if($pos=strrpos($path,'.')){ + $extention=substr($path,$pos); + }else{ + $extention=''; + } $tmpFile=OC_Helper::tmpFile($extention); $target=fopen($tmpFile,'w'); $count=OC_Helper::streamCopy($source,$target); From 72947e46d1a4c6066f561d3e49c032f23589e4e1 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Sat, 3 Mar 2012 20:45:17 +0100 Subject: [PATCH 021/132] small improvement for is_dir --- lib/filestorage/local.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/filestorage/local.php b/lib/filestorage/local.php index 750a1fb36d..25c3d76740 100644 --- a/lib/filestorage/local.php +++ b/lib/filestorage/local.php @@ -21,7 +21,10 @@ class OC_Filestorage_Local extends OC_Filestorage{ return opendir($this->datadir.$path); } public function is_dir($path){ - return @is_dir($this->datadir.$path); + if(substr($path,-1)=='/'){ + $path=substr($path,0,-1); + } + return is_dir($this->datadir.$path); } public function is_file($path){ return is_file($this->datadir.$path); From a5df3f8ea74b53d914a9ebd2687f8ab73b0a201b Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Sat, 3 Mar 2012 20:46:46 +0100 Subject: [PATCH 022/132] allow transparent opening of zip files from the web interface --- apps/files_archive/appinfo/app.php | 4 +++ apps/files_archive/js/archive.js | 15 +++++++++ apps/files_archive/lib/storage.php | 50 +++++++++++++++++++++++++++--- 3 files changed, 64 insertions(+), 5 deletions(-) create mode 100644 apps/files_archive/js/archive.js diff --git a/apps/files_archive/appinfo/app.php b/apps/files_archive/appinfo/app.php index e75f6fa055..693c28d98a 100644 --- a/apps/files_archive/appinfo/app.php +++ b/apps/files_archive/appinfo/app.php @@ -12,3 +12,7 @@ foreach(array('ZIP') as $type){ } OC::$CLASSPATH['OC_Filestorage_Archive']='apps/files_archive/lib/storage.php'; + +OC_Hook::connect('OC_Filesystem','get_mountpoint','OC_Filestorage_Archive','autoMount'); + +OC_Util::addScript( 'files_archive', 'archive' ); diff --git a/apps/files_archive/js/archive.js b/apps/files_archive/js/archive.js new file mode 100644 index 0000000000..ec316c7bf2 --- /dev/null +++ b/apps/files_archive/js/archive.js @@ -0,0 +1,15 @@ +/** + * Copyright (c) 2012 Robin Appelman + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +$(document).ready(function() { + if(typeof FileActions!=='undefined'){ + FileActions.register('application/zip','Open','',function(filename){ + window.location='index.php?dir='+encodeURIComponent($('#dir').val()).replace(/%2F/g, '/')+'/'+encodeURIComponent(filename); + }); + FileActions.setDefault('application/zip','Open'); + } +}); diff --git a/apps/files_archive/lib/storage.php b/apps/files_archive/lib/storage.php index 4f4c0ef2ab..72a96ca5a5 100644 --- a/apps/files_archive/lib/storage.php +++ b/apps/files_archive/lib/storage.php @@ -13,10 +13,13 @@ class OC_Filestorage_Archive extends OC_Filestorage_Common{ */ private $archive; private $path; + private static $mounted=array(); + private static $enableAutomount=true; + private static $rootView; private function stripPath($path){//files should never start with / if(substr($path,0,1)=='/'){ - return substr($path,1); + $path=substr($path,1); } return $path; } @@ -52,9 +55,14 @@ class OC_Filestorage_Archive extends OC_Filestorage_Common{ if($path==''){ $stat=stat($this->path); }else{ - $stat=array(); - $stat['mtime']=$this->archive->mtime($path); - $stat['size']=$this->archive->filesize($path); + if($this->is_dir($path)){ + $stat=array('size'=>0); + $stat['mtime']=filemtime($this->path); + }else{ + $stat=array(); + $stat['mtime']=$this->archive->mtime($path); + $stat['size']=$this->archive->filesize($path); + } } $stat['ctime']=$ctime; return $stat; @@ -64,7 +72,11 @@ class OC_Filestorage_Archive extends OC_Filestorage_Common{ if($path==''){ return 'dir'; } - return $this->archive->fileExists($path.'/')?'dir':'file'; + if(substr($path,-1)=='/'){ + return $this->archive->fileExists($path)?'dir':'file'; + }else{ + return $this->archive->fileExists($path.'/')?'dir':'file'; + } } public function is_readable($path){ return is_readable($this->path); @@ -99,4 +111,32 @@ class OC_Filestorage_Archive extends OC_Filestorage_Common{ return false;//not supported } } + + /** + * automount paths from file hooks + * @param aray params + */ + public static function autoMount($params){ + if(!self::$enableAutomount){ + return; + } + $path=$params['path']; + if(!self::$rootView){ + self::$rootView=new OC_FilesystemView(''); + } + self::$enableAutomount=false;//prevent recursion + $supported=array('zip'); + foreach($supported as $type){ + $ext='.'.$type.'/'; + if(($pos=strpos(strtolower($path),$ext))!==false){ + $archive=substr($path,0,$pos+strlen($ext)-1); + if(self::$rootView->file_exists($archive) and array_search($archive,self::$mounted)===false){ + $localArchive=self::$rootView->getLocalFile($archive); + OC_Filesystem::mount('OC_Filestorage_Archive',array('archive'=>$localArchive),$archive.'/'); + self::$mounted[]=$archive; + } + } + } + self::$enableAutomount=true; + } } From af214d9dcd0f4c6058c91875e10f38824582aa74 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Sat, 3 Mar 2012 22:04:34 +0100 Subject: [PATCH 023/132] change gallary scanning to support gallaries inside archives --- apps/gallery/ajax/galleryOp.php | 2 +- apps/gallery/js/album_cover.js | 2 +- apps/gallery/lib/scanner.php | 27 +++++++++++---------------- 3 files changed, 13 insertions(+), 18 deletions(-) diff --git a/apps/gallery/ajax/galleryOp.php b/apps/gallery/ajax/galleryOp.php index f07814056a..c19344c0fb 100644 --- a/apps/gallery/ajax/galleryOp.php +++ b/apps/gallery/ajax/galleryOp.php @@ -62,7 +62,7 @@ function handleFilescan($cleanup) { function handlePartialCreate($path) { if (empty($path)) OC_JSON::error(array('cause' => 'No path specified')); - if (!OC_Filesystem::is_dir($path)) OC_JSON::error(array('cause' => 'Invalid path given')); + if (!OC_Filesystem::is_dir($path.'/')) OC_JSON::error(array('cause' => 'Invalid path given')); $album = OC_Gallery_Album::find(OC_User::getUser(), null, $path); $albums = array(); diff --git a/apps/gallery/js/album_cover.js b/apps/gallery/js/album_cover.js index 4ddac2f211..d328a2d58e 100644 --- a/apps/gallery/js/album_cover.js +++ b/apps/gallery/js/album_cover.js @@ -53,7 +53,7 @@ function scanForAlbums(cleanup) { } $('#scanprogressbar').progressbar({ value: (albumCounter/totalAlbums)*100 }).fadeIn(); for(var a in r.paths) { - $.getJSON('ajax/galleryOp.php?operation=partial_create&path='+r.paths[a], function(r) { + $.getJSON('ajax/galleryOp.php',{operation:'partial_create','path':r.paths[a]}, function(r) { if (r.status == 'success') { Albums.add(r.album_details.albumName, r.album_details.imagesCount); diff --git a/apps/gallery/lib/scanner.php b/apps/gallery/lib/scanner.php index 64efb006ad..9c381acf38 100644 --- a/apps/gallery/lib/scanner.php +++ b/apps/gallery/lib/scanner.php @@ -53,7 +53,7 @@ class OC_Gallery_Scanner { $current_album = array('name'=> $path, 'imagesCount' => 0, 'images' => array()); $current_album['name'] = self::createName($current_album['name']); - if ($dh = OC_Filesystem::opendir($path)) { + if ($dh = OC_Filesystem::opendir($path.'/')) { while (($filename = readdir($dh)) !== false) { $filepath = ($path[strlen($path)-1]=='/'?$path:$path.'/').$filename; if (substr($filename, 0, 1) == '.') continue; @@ -103,21 +103,16 @@ class OC_Gallery_Scanner { } public static function find_paths($path) { - $ret = array(); - $dirres; - $addpath = FALSE; - if (($dirres = OC_Filesystem::opendir($path)) == FALSE) return $ret; - - while (($file = readdir($dirres)) != FALSE) { - if ($file[0] == '.') continue; - if (OC_Filesystem::is_dir($path.$file)) - $ret = array_merge($ret, self::find_paths($path.$file.'/')); - if (self::isPhoto($path.$file)) $addpath = TRUE; - } - - if ($addpath) $ret[] = urlencode($path); - - return $ret; + $images=OC_FileCache::searchByMime('image'); + $paths=array(); + foreach($images as $image){ + $path=dirname($image); + if(array_search($path,$paths)===false){ + error_log($path); + $paths[]=$path; + } + } + return $paths; } } ?> From f06858689f9709d3859f814ca57dfa54b9ed0865 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Sat, 3 Mar 2012 22:12:17 +0100 Subject: [PATCH 024/132] revert an accidental change --- lib/filestorage/local.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/filestorage/local.php b/lib/filestorage/local.php index 25c3d76740..688501aee9 100644 --- a/lib/filestorage/local.php +++ b/lib/filestorage/local.php @@ -79,9 +79,8 @@ class OC_Filestorage_Local extends OC_Filestorage{ public function file_get_contents($path){ return file_get_contents($this->datadir.$path); } - public function file_put_contents($path,$data=null){ - if($return=file_put_contents($this->datadir.$path,$data)){ - } + public function file_put_contents($path,$data){ + return file_put_contents($this->datadir.$path,$data); } public function unlink($path){ return $this->delTree($path); From c411826fe5e7662fb0f6dc5fbcb074c68b467ea4 Mon Sep 17 00:00:00 2001 From: Bartek Przybylski Date: Sun, 4 Mar 2012 00:35:37 +0100 Subject: [PATCH 025/132] moving gallery op to one file, migrate gallery dialogs to oc dialogs --- apps/gallery/ajax/galleryOp.php | 19 +++++++ apps/gallery/ajax/getAlbums.php | 41 --------------- apps/gallery/js/album_cover.js | 92 +++++++++++---------------------- apps/gallery/lib/scanner.php | 2 +- core/js/oc-dialogs.js | 28 +++++----- 5 files changed, 66 insertions(+), 116 deletions(-) delete mode 100644 apps/gallery/ajax/getAlbums.php diff --git a/apps/gallery/ajax/galleryOp.php b/apps/gallery/ajax/galleryOp.php index c19344c0fb..e768ce00c1 100644 --- a/apps/gallery/ajax/galleryOp.php +++ b/apps/gallery/ajax/galleryOp.php @@ -88,6 +88,22 @@ function handleStoreSettings($root, $order) { OC_JSON::success(array('rescan' => $rescan)); } + +function handleGetGalleries() { + $a = array(); + + $result = OC_Gallery_Album::find(OC_User::getUser()); + + while ($r = $result->fetchRow()) { + $album_name = $r['album_name']; + $tmp_res = OC_Gallery_Photo::find($r['album_id']); + + $a[] = array('name' => utf8_encode($album_name), 'numOfItems' => min($tmp_res->numRows(), 10), 'bgPath' => OC::$WEBROOT.'/data/'.OC_User::getUser().'/gallery/'.$album_name.'.png'); + } + + OC_JSON::success(array('albums'=>$a)); +} + if ($_GET['operation']) { switch($_GET['operation']) { case 'rename': @@ -113,6 +129,9 @@ if ($_GET['operation']) { case 'store_settings': handleStoreSettings($_GET['root'], $_GET['order']); break; + case 'get_galleries': + handleGetGalleries(); + break; default: OC_JSON::error(array('cause' => 'Unknown operation')); } diff --git a/apps/gallery/ajax/getAlbums.php b/apps/gallery/ajax/getAlbums.php deleted file mode 100644 index be87af2abd..0000000000 --- a/apps/gallery/ajax/getAlbums.php +++ /dev/null @@ -1,41 +0,0 @@ -. -* -*/ - -require_once('../../../lib/base.php'); -OC_JSON::checkLoggedIn(); -OC_JSON::checkAppEnabled('gallery'); - -$a = array(); - -$result = OC_Gallery_Album::find(OC_User::getUser()); - -while ($r = $result->fetchRow()) { - $album_name = $r['album_name']; - $tmp_res = OC_Gallery_Photo::find($r['album_id']); - - $a[] = array('name' => utf8_encode($album_name), 'numOfItems' => min($tmp_res->numRows(), 10), 'bgPath' => OC::$WEBROOT.'/data/'.OC_User::getUser().'/gallery/'.$album_name.'.png'); -} - -OC_JSON::success(array('albums'=>$a)); - -?> diff --git a/apps/gallery/js/album_cover.js b/apps/gallery/js/album_cover.js index d328a2d58e..e63bed05fe 100644 --- a/apps/gallery/js/album_cover.js +++ b/apps/gallery/js/album_cover.js @@ -1,6 +1,6 @@ var actual_cover; $(document).ready(function() { - $.getJSON('ajax/getAlbums.php', function(r) { + $.getJSON('ajax/galleryOp.php', {operation: 'get_galleries'}, function(r) { if (r.status == 'success') { for (var i in r.albums) { var a = r.albums[i]; @@ -81,71 +81,39 @@ function scanForAlbums(cleanup) { } function galleryRemove(albumName) { - // a workaround for a flaw in the demo system (http://dev.jqueryui.com/ticket/4375), ignore! - $( "#dialog:ui-dialog" ).dialog( "destroy" ); - $('#albumName', $("#dialog-confirm")).text(albumName); - - $( '#dialog-confirm' ).dialog({ - resizable: false, - height:150, - buttons: [{ - text: t('gallery', 'OK'), - click: function() { - $.getJSON("ajax/galleryOp.php", {operation: "remove", name: albumName}, function(r) { - if (r.status == "success") { - $(".gallery_album_box").filterAttr('data-album',albumName).remove(); - Albums.remove(albumName); - } else { - alert("Error: " + r.cause); - } - $('#dialog-confirm').dialog('close'); - }); - }}, - { - text: t('gallery', 'Cancel'), - click: function() { - $( this ).dialog( 'close' ); - }}] + OC.dialogs.confirm(t('gallery', 'Do you want to remove album ') + decodeURIComponent(escape(albumName)), + t('gallery', 'Remove confirmation'), + function(decision) { + if (decision) { + $.getJSON("ajax/galleryOp.php", {operation: "remove", name: decodeURIComponent(escape(albumName))}, function(r) { + if (r.status == "success") { + $(".gallery_album_box").filterAttr('data-album',albumName).remove(); + Albums.remove(albumName); + } else { + OC.dialogs.alert(r.cause, "Error"); + } + }); + } }); } function galleryRename(name) { - $('#name', $('#dialog-form')).val(name); - $( "#dialog-form" ).dialog({ - height: 140, - width: 350, - modal: false, - buttons: [{ - text: t('gallery', 'Change name'), - click: function() { - var newname = $('#name', $('#dialog-form')).val(); - if (newname == name || newname == '') { - $(this).dialog("close"); - return; - } - if (Albums.find(newname)) { - alert("Album ", newname, " exists"); - $(this).dialog("close"); - return; - } - $.getJSON('ajax/galleryOp.php', {operation: 'rename', oldname: name, newname: newname}, function(r) { - if (r.status == "success") { - Albums.rename($(".gallery_album_box").filterAttr('data-album',name), newname); - } else { - alert("Error: " + r.cause); - } - $('#dialog-form').dialog('close'); - }); - - } - }, - { - text: t('gallery', 'Cancel'), - click: function() { - $( this ).dialog('close'); - } - } - ], + OC.dialogs.prompt(t('gallery', 'New album name'), + t('gallery', 'Change name'), + name, + function(newname) { + if (newname == name || newname == '') return; + if (Albums.find(newname)) { + OC.dialogs.alert('Album ' + newname + ' exists', 'Alert'); + return; + } + $.getJSON('ajax/galleryOp.php', {operation: 'rename', oldname: name, newname: newname}, function(r) { + if (r.status == 'success') { + Albums.rename($(".gallery_album_box").filterAttr('data-album',name), newname); + } else { + OC.dialogs.alert('Error: ' + r.cause, 'Error'); + } + }); }); } diff --git a/apps/gallery/lib/scanner.php b/apps/gallery/lib/scanner.php index 9c381acf38..19906c0715 100644 --- a/apps/gallery/lib/scanner.php +++ b/apps/gallery/lib/scanner.php @@ -64,7 +64,7 @@ class OC_Gallery_Scanner { } $current_album['imagesCount'] = count($current_album['images']); $albums['imagesCount'] = $current_album['imagesCount']; - $albums['albumName'] = $current_album['name']; + $albums['albumName'] = utf8_encode($current_album['name']); $result = OC_Gallery_Album::find(OC_User::getUser(), /*$current_album['name']*/ null, $path); // don't duplicate galleries with same path (bug oc-33) diff --git a/core/js/oc-dialogs.js b/core/js/oc-dialogs.js index de67c342a7..9ce2bae164 100644 --- a/core/js/oc-dialogs.js +++ b/core/js/oc-dialogs.js @@ -52,7 +52,7 @@ OCdialogs = { */ confirm:function(text, title, callback) { var content = '

      '+text+'

      '; - OCdialogs.message(content, title, OCdialogs.ALERT_DIALOG, OCdialogs.YES_NO_BUTTON, callback); + OCdialogs.message(content, title, OCdialogs.ALERT_DIALOG, OCdialogs.YES_NO_BUTTONS, callback); }, /** * prompt for user input @@ -60,8 +60,8 @@ OCdialogs = { * @param title dialog title * @param callback which will be triggered when user press OK (input text will be passed to callback) */ - prompt:function(text, title, callback) { - var content = '

      '+text+':

      '; + prompt:function(text, title, default_value, callback) { + var content = '

      '+text+':

      '; OCdialogs.message(content, title, OCdialogs.PROMPT_DIALOG, OCdialogs.OK_CANCEL_BUTTONS, callback); }, /** @@ -131,15 +131,19 @@ OCdialogs = { } return $(element).val(); }, - prompt_ok_handler: function(callback, c_id){callback(true, $(c_id + " input#oc-dialog-prompt-input").val()); $(c_id).dialog('close');}, + prompt_ok_handler: function(callback, c_id) { $(c_id).dialog('close'); if (callback != undefined) callback($(c_id + " input#oc-dialog-prompt-input").val()); }, form_ok_handler: function(callback, c_id) { - var r = []; - var c = 0; - $(c_id + ' input').each(function(i, elem) { - r[c] = {name: $(elem).attr('name'), value: OCdialogs.determineValue(elem)}; - c++; - }); - $(c_id).dialog('close'); - callback(r); + if (callback != undefined) { + var r = []; + var c = 0; + $(c_id + ' input').each(function(i, elem) { + r[c] = {name: $(elem).attr('name'), value: OCdialogs.determineValue(elem)}; + c++; + }); + $(c_id).dialog('close'); + callback(r); + } else { + $(c_id).dialog('close'); + } } }; From 0a78849391761a616f392b8ad5468318dd84b4ff Mon Sep 17 00:00:00 2001 From: Bartek Przybylski Date: Sun, 4 Mar 2012 18:28:41 +0100 Subject: [PATCH 026/132] multilevel gallery --- apps/gallery/ajax/galleryOp.php | 32 ++++++++++++---- apps/gallery/appinfo/database.xml | 34 ++++++++++------- apps/gallery/appinfo/info.xml | 2 +- apps/gallery/css/styles.css | 11 +++--- apps/gallery/js/album_cover.js | 62 ++++++++++++++++++++++--------- apps/gallery/js/albums.js | 13 ++++++- apps/gallery/lib/album.php | 22 ++++++++--- apps/gallery/lib/scanner.php | 13 ++----- apps/gallery/templates/index.php | 11 +++++- 9 files changed, 136 insertions(+), 64 deletions(-) diff --git a/apps/gallery/ajax/galleryOp.php b/apps/gallery/ajax/galleryOp.php index e768ce00c1..ee919daeac 100644 --- a/apps/gallery/ajax/galleryOp.php +++ b/apps/gallery/ajax/galleryOp.php @@ -41,7 +41,6 @@ function handleRemove($name) { function handleGetThumbnails($albumname) { OC_Response::enableCaching(3600 * 24); // 24 hour - error_log(htmlentities($albumname)); $thumbnail = OC::$CONFIG_DATADIRECTORY.'/../gallery/'.urldecode($albumname).'.png'; header('Content-Type: '.OC_Image::getMimeTypeForFile($thumbnail)); OC_Response::sendFile($thumbnail); @@ -88,20 +87,36 @@ function handleStoreSettings($root, $order) { OC_JSON::success(array('rescan' => $rescan)); } - -function handleGetGalleries() { +function handleGetGallery($path) { $a = array(); + $root = OC_Preferences::getValue(OC_User::getUser(),'gallery', 'root', '/'); + if (strlen($root) > 1) + $path = $root.'/'.trim($path, '/'); + else + $path = '/'.ltrim($path, '/'); + if (strlen($path) > 1) $path = rtrim($path, '/'); + error_log($path); + $result = OC_Gallery_Album::find(OC_User::getUser(), null, $path); + $album_details = $result->fetchRow(); - $result = OC_Gallery_Album::find(OC_User::getUser()); + $result = OC_Gallery_Album::find(OC_User::getUser(), null, null, $path); while ($r = $result->fetchRow()) { $album_name = $r['album_name']; $tmp_res = OC_Gallery_Photo::find($r['album_id']); - $a[] = array('name' => utf8_encode($album_name), 'numOfItems' => min($tmp_res->numRows(), 10), 'bgPath' => OC::$WEBROOT.'/data/'.OC_User::getUser().'/gallery/'.$album_name.'.png'); + $a[] = array('name' => utf8_encode($album_name), 'numOfItems' => min($tmp_res->numRows(), 10)); + } + + $result = OC_Gallery_Photo::find($album_details['album_id']); + + $p = array(); + + while ($r = $result->fetchRow()) { + $p[] = utf8_encode($r['file_path']); } - OC_JSON::success(array('albums'=>$a)); + OC_JSON::success(array('albums'=>$a, 'photos'=>$p)); } if ($_GET['operation']) { @@ -130,7 +145,10 @@ if ($_GET['operation']) { handleStoreSettings($_GET['root'], $_GET['order']); break; case 'get_galleries': - handleGetGalleries(); + handleGetGalleries($_GET['path']); + break; + case 'get_gallery': + handleGetGallery($_GET['path']); break; default: OC_JSON::error(array('cause' => 'Unknown operation')); diff --git a/apps/gallery/appinfo/database.xml b/apps/gallery/appinfo/database.xml index db88e4c1b5..62fdbee9cd 100644 --- a/apps/gallery/appinfo/database.xml +++ b/apps/gallery/appinfo/database.xml @@ -11,9 +11,9 @@ album_id integer 0 - true - 1 - 4 + true + 1 + 4 uid_owner @@ -27,12 +27,18 @@ true 100 - - album_path - text - true - 100 - + + album_path + text + true + 100 + + + parent_path + text + true + 100 + @@ -42,16 +48,16 @@ photo_idinteger0 - true - 1 - 4 + true + 1 + 4 album_id integer 0 - true - 4 + true + 4 file_path diff --git a/apps/gallery/appinfo/info.xml b/apps/gallery/appinfo/info.xml index 9aecb0c781..19c5dc8b25 100644 --- a/apps/gallery/appinfo/info.xml +++ b/apps/gallery/appinfo/info.xml @@ -2,7 +2,7 @@ gallery Gallery - 0.3 + 0.4 AGPL Bartek Przybylski 2 diff --git a/apps/gallery/css/styles.css b/apps/gallery/css/styles.css index da94f9ac9e..1bff610c78 100644 --- a/apps/gallery/css/styles.css +++ b/apps/gallery/css/styles.css @@ -1,13 +1,14 @@ div#gallery_list { margin: 4.5em 2em 0 2em; } div#gallery_list.leftcontent { padding-top: 15pt; margin: 0; position: absolute; bottom:0px; text-align: center; overflow: auto; } -div.gallery_album_box { width: 200px; position:relative; text-align: center; border: 0; display: inline-block; margin: 5pt; vertical-align: top; padding: 5px 5px 5px 5px; position: relative; -webkit-transition: color 0.5s ease-in-out; -o-transition: color 0.5s ease-in-out; -moz-transition: color 0.5s ease-in-out;color: #BBB;} -div.gallery_album_box h1 { font-size: 9pt; font-family: Verdana; } +div.gallery_box { width: 200px; position:relative; text-align: center; border: 0; display: inline-block; margin: 5pt; vertical-align: top; padding: 5px 5px 5px 5px; position: relative; -webkit-transition: color 0.5s ease-in-out; -o-transition: color 0.5s ease-in-out; -moz-transition: color 0.5s ease-in-out;color: #BBB;} +div.album {border: 1px solid #e0e0e0; border-radius: 7px;} +div.gallery_box h1 { font-size: 9pt; font-family: Verdana; } div.gallery_album_decoration { width: 200px; position: absolute; border: 0; height: 20px; top: 5px; text-align:right; vertical-align:middle; background-color: #eee; opacity: 0; -webkit-transition: opacity 0.5s ease-in-out; -moz-transition: opacity 0.5s ease-in-out; -o-transition: opacity 0.5s ease-in-out; border-bottom-right-radius: 7px; border-bottom-left-radius: 7px; -moz-border-radius-bottomright: 7px; -moz-border-radius-bottomleft:7px;} -div.gallery_album_box:hover { color: black; } -div.gallery_album_box:hover div.gallery_album_decoration { opacity: 0.7;} +div.gallery_box:hover { color: black; } +div.gallery_box:hover div.gallery_album_decoration { opacity: 0.7;} div.gallery_album_decoration a {padding: 0 4pt; cursor: pointer;} div.gallery_album_cover { width: 200px; height: 200px; border: 0; padding: 0; position:relative;} -div.gallery_album_box:hover div.gallery_control_overlay { opacity:0.5 } +div.gallery_box:hover div.gallery_control_overlay { opacity:0.5 } div.gallery_control_overlay a { color:white; } #gallery_images.rightcontent { padding:10px 5px; bottom: 0px; overflow: auto; right:0px} #scan { position:absolute; right:13.5em; top:0em; } diff --git a/apps/gallery/js/album_cover.js b/apps/gallery/js/album_cover.js index e63bed05fe..98f2907281 100644 --- a/apps/gallery/js/album_cover.js +++ b/apps/gallery/js/album_cover.js @@ -1,34 +1,62 @@ var actual_cover; -$(document).ready(function() { - $.getJSON('ajax/galleryOp.php', {operation: 'get_galleries'}, function(r) { +var paths = ''; +var crumbCount = 0; +$(document).ready(returnToElement(0)); + +function returnToElement(num) { + while (crumbCount != num) { + $('#g-album-navigation .last').remove(); + $('#g-album-navigation .crumb :last').parent().addClass('last'); + crumbCount--; + paths = paths.substring(0, paths.lastIndexOf('\/')); + } + $.getJSON('ajax/galleryOp.php', {operation: 'get_gallery', path: paths }, albumClickHandler); +} + +function albumClick(e) { + var title = decodeURIComponent(escape(e.data.title)); + paths += '/' + title; + crumbCount++; + $.getJSON('ajax/galleryOp.php', {operation: 'get_gallery', path: paths }, albumClickHandler); + if ($('#g-album-navigation :last-child')) + $('#g-album-navigation :last-child').removeClass('last'); + $('#g-album-navigation').append(''); +} + +function albumClickHandler(r) { + Albums.photos = []; + Albums.albums = []; if (r.status == 'success') { for (var i in r.albums) { var a = r.albums[i]; Albums.add(a.name, a.numOfItems); } + for (var i in r.photos) { + Albums.photos.push(r.photos[i]); + } var targetDiv = document.getElementById('gallery_list'); if (targetDiv) { $(targetDiv).html(''); Albums.display(targetDiv); - $('#gallery_list').sortable({revert:true}); - $('.gallery_album_box').each(function(i, e) { - $(e).draggable({connectToSortable: '#gallery_list', handle: '.dummy'}) + //$('#gallery_list').sortable({revert:true}); + $('.album').each(function(i, el) { + $(el).click({title:$(el).attr('title')}, albumClick); + //$(el).draggable({connectToSortable: '#gallery_list', handle: '.dummy'}); }); } else { - alert('Error occured: no such layer `gallery_list`'); + OC.dialogs.alert(t('gallery', 'Error: no such layer `gallery_list`'), t('gallery', 'Internal error')); } } else { - alert('Error occured: ' + r.message); + OC.dialogs.alert(t('gallery', 'Error: ') + r.message, t('gallery', 'Internal error')); } - }); -}); +} function createNewAlbum() { var name = prompt("album name", ""); if (name != null && name != "") { $.getJSON("ajax/createAlbum.php", {album_name: name}, function(r) { if (r.status == "success") { - var v = ''; + var v = ''; $('div#gallery_list').append(v); } }); @@ -53,11 +81,7 @@ function scanForAlbums(cleanup) { } $('#scanprogressbar').progressbar({ value: (albumCounter/totalAlbums)*100 }).fadeIn(); for(var a in r.paths) { - $.getJSON('ajax/galleryOp.php',{operation:'partial_create','path':r.paths[a]}, function(r) { - - if (r.status == 'success') { - Albums.add(r.album_details.albumName, r.album_details.imagesCount); - } + $.getJSON('ajax/galleryOp.php',{operation:'partial_create','path':r.paths[a]}, function(r) { albumCounter++; $('#scanprogressbar').progressbar({ value: (albumCounter/totalAlbums)*100 }); @@ -66,7 +90,9 @@ function scanForAlbums(cleanup) { var targetDiv = document.getElementById('gallery_list'); if (targetDiv) { targetDiv.innerHTML = ''; - Albums.display(targetDiv); + Albums.photos = []; + Albums.albums = []; + returnToElement(0); } else { alert('Error occured: no such layer `gallery_list`'); } @@ -87,7 +113,7 @@ function galleryRemove(albumName) { if (decision) { $.getJSON("ajax/galleryOp.php", {operation: "remove", name: decodeURIComponent(escape(albumName))}, function(r) { if (r.status == "success") { - $(".gallery_album_box").filterAttr('data-album',albumName).remove(); + $(".gallery_box").filterAttr('data-album',albumName).remove(); Albums.remove(albumName); } else { OC.dialogs.alert(r.cause, "Error"); @@ -109,7 +135,7 @@ function galleryRename(name) { } $.getJSON('ajax/galleryOp.php', {operation: 'rename', oldname: name, newname: newname}, function(r) { if (r.status == 'success') { - Albums.rename($(".gallery_album_box").filterAttr('data-album',name), newname); + Albums.rename($(".gallery_box").filterAttr('data-album',name), newname); } else { OC.dialogs.alert('Error: ' + r.cause, 'Error'); } diff --git a/apps/gallery/js/albums.js b/apps/gallery/js/albums.js index adecd24cc7..c12cbacf5b 100644 --- a/apps/gallery/js/albums.js +++ b/apps/gallery/js/albums.js @@ -7,6 +7,7 @@ Albums={ // to display to user as preview picture when scrolling throught // the album cover albums:new Array(), + photos:new Array(), // add simply adds new album to internal structure // however albums names must be unique so other // album with the same name wont be insered, @@ -41,10 +42,11 @@ Albums={ // displays gallery in linear representation // on given element, and apply default styles for gallery display: function(element) { - var displayTemplate = ''; + var displayTemplate = ''; for (var i in Albums.albums) { var a = Albums.albums[i]; var local=$(displayTemplate); + local.attr('title', a.name); local.attr('data-album',a.name); $(".gallery_album_decoration a.rename", local).bind('click', {name: a.name},function(event){ event.preventDefault(); @@ -54,7 +56,7 @@ Albums={ event.preventDefault(); galleryRemove(event.data.name); }); - $("a.view", local).attr('href','?view='+decodeURIComponent(escape(a.name))); + // $("a.view", local).attr('href','?view='+decodeURIComponent(escape(a.name))); $('h1',local).text(decodeURIComponent(escape(a.name))); $(".gallery_album_cover", local).attr('title',decodeURIComponent(escape(a.name))); $(".gallery_album_cover", local).css('background-repeat', 'no-repeat'); @@ -73,6 +75,13 @@ Albums={ }); $(element).append(local); } + var photoDisplayTemplate = ''; + for (var i in Albums.photos) { + $(element).append(photoDisplayTemplate.replace("IMGPATH", escape(Albums.photos[i])).replace("URLPATH", escape(Albums.photos[i]))); + } + $("a[rel=images]").fancybox({ + 'titlePosition': 'inside' + }); }, rename: function(element, new_name) { if (new_name) { diff --git a/apps/gallery/lib/album.php b/apps/gallery/lib/album.php index d1405333ac..317e8209de 100644 --- a/apps/gallery/lib/album.php +++ b/apps/gallery/lib/album.php @@ -23,10 +23,11 @@ class OC_Gallery_Album { public static function create($owner, $name, $path){ - $stmt = OC_DB::prepare('INSERT INTO *PREFIX*gallery_albums (uid_owner, album_name, album_path) VALUES (?, ?, ?)'); - $stmt->execute(array($owner, $name, $path)); + $id = self::getParentPath($path); + $stmt = OC_DB::prepare('INSERT INTO *PREFIX*gallery_albums (uid_owner, album_name, album_path, parent_path) VALUES (?, ?, ?, ?)'); + $stmt->execute(array($owner, $name, $path, $id)); } - + public static function rename($oldname, $newname, $owner) { $stmt = OC_DB::prepare('UPDATE *PREFIX*gallery_albums SET album_name=? WHERE uid_owner=? AND album_name=?'); $stmt->execute(array($newname, $owner, $oldname)); @@ -39,7 +40,14 @@ class OC_Gallery_Album { self::remove(OC_User::getUser(), $r['album_name']); } } - + + public static function getParentPath($path) { + if (strlen($path)==1) return ''; + $path = substr($path, 0, strrpos($path, '/')); + if ($path == '') $path = '/'; + return $path; + } + public static function remove($owner, $name=null) { $sql = 'DELETE FROM *PREFIX*gallery_albums WHERE uid_owner = ?'; $args = array($owner); @@ -66,7 +74,7 @@ class OC_Gallery_Album { } } - public static function find($owner, $name=null, $path=null){ + public static function find($owner, $name=null, $path=null, $parent=null){ $sql = 'SELECT * FROM *PREFIX*gallery_albums WHERE uid_owner = ?'; $args = array($owner); if (!is_null($name)){ @@ -77,6 +85,10 @@ class OC_Gallery_Album { $sql .= ' AND album_path = ?'; $args[] = $path; } + if (!is_null($parent)){ + $sql .= ' AND parent_path = ?'; + $args[] = $parent; + } $order = OC_Preferences::getValue(OC_User::getUser(), 'gallery', 'order', 'ASC'); $sql .= ' ORDER BY album_name ' . $order; diff --git a/apps/gallery/lib/scanner.php b/apps/gallery/lib/scanner.php index 19906c0715..8dcd77821c 100644 --- a/apps/gallery/lib/scanner.php +++ b/apps/gallery/lib/scanner.php @@ -21,7 +21,7 @@ * */ -require_once('base.php'); // base lib +require_once('base.php'); require_once('images_utils.php'); class OC_Gallery_Scanner { @@ -40,20 +40,14 @@ class OC_Gallery_Scanner { } public static function createName($name) { - $root = OC_Preferences::getValue(OC_User::getUser(), 'gallery', 'root', '/'); - $name = str_replace('/', '.', str_replace(OC::$CONFIG_DATADIRECTORY, '', $name)); - if (substr($name, 0, strlen($root)) == str_replace('/','.',$root)) { - $name = substr($name, strlen($root)); - } - $name = ($name==='.') ? 'main' : trim($name,'.'); - return $name; + return basename($name); } public static function scanDir($path, &$albums) { $current_album = array('name'=> $path, 'imagesCount' => 0, 'images' => array()); $current_album['name'] = self::createName($current_album['name']); - if ($dh = OC_Filesystem::opendir($path.'/')) { + if ($dh = OC_Filesystem::opendir($path)) { while (($filename = readdir($dh)) !== false) { $filepath = ($path[strlen($path)-1]=='/'?$path:$path.'/').$filename; if (substr($filename, 0, 1) == '.') continue; @@ -108,7 +102,6 @@ class OC_Gallery_Scanner { foreach($images as $image){ $path=dirname($image); if(array_search($path,$paths)===false){ - error_log($path); $paths[]=$path; } } diff --git a/apps/gallery/templates/index.php b/apps/gallery/templates/index.php index 1b8d53e82d..7f0281e6a3 100644 --- a/apps/gallery/templates/index.php +++ b/apps/gallery/templates/index.php @@ -2,6 +2,10 @@ OC_Util::addStyle('gallery', 'styles'); OC_Util::addScript('gallery', 'albums'); OC_Util::addScript('gallery', 'album_cover'); +OC_Util::addStyle('files', 'files'); +OC_Util::addScript('files_imageviewer', 'jquery.mousewheel-3.0.4.pack'); +OC_Util::addScript('files_imageviewer', 'jquery.fancybox-1.3.4.pack'); +OC_Util::addStyle( 'files_imageviewer', 'jquery.fancybox-1.3.4' ); $l = new OC_L10N('gallery'); ?> @@ -9,10 +13,13 @@ $l = new OC_L10N('gallery');
      -
      -
      +
      +
      + main +
      +
      From fb88bdba69443e81f8bed5172510b4308897ae47 Mon Sep 17 00:00:00 2001 From: rok Date: Fri, 2 Mar 2012 21:32:17 +0100 Subject: [PATCH 027/132] Ability to save an arbitrary number of external sites --- apps/external/ajax/setsites.php | 25 +++++++ apps/external/ajax/seturls.php | 24 ------- apps/external/appinfo/app.php | 58 ++++++++-------- apps/external/css/style.css | 14 ++++ apps/external/index.php | 59 +++++++++-------- apps/external/js/admin.js | 99 +++++++++++++--------------- apps/external/lib/external.php | 36 ++++++++++ apps/external/settings.php | 12 ---- apps/external/templates/settings.php | 30 ++++----- 9 files changed, 191 insertions(+), 166 deletions(-) create mode 100644 apps/external/ajax/setsites.php delete mode 100644 apps/external/ajax/seturls.php create mode 100644 apps/external/css/style.css create mode 100644 apps/external/lib/external.php diff --git a/apps/external/ajax/setsites.php b/apps/external/ajax/setsites.php new file mode 100644 index 0000000000..0537b7ea58 --- /dev/null +++ b/apps/external/ajax/setsites.php @@ -0,0 +1,25 @@ + + * This file is licensed under the Affero General Public License version 3 or later. + * See the COPYING-README file. + */ + +require_once('../../../lib/base.php'); +OC_Util::checkAdminUser(); + +$sites = array(); +for ($i = 0; $i < sizeof($_POST['site_name']); $i++) { + if (!empty($_POST['site_name'][$i]) && !empty($_POST['site_url'][$i])) { + array_push($sites, array($_POST['site_name'][$i], $_POST['site_url'][$i])); + } +} + +if (sizeof($sites) == 0) + OC_Appconfig::deleteKey('external', 'sites'); +else + OC_Appconfig::setValue('external', 'sites', json_encode($sites)); + +echo 'true'; +?> diff --git a/apps/external/ajax/seturls.php b/apps/external/ajax/seturls.php deleted file mode 100644 index e994385a19..0000000000 --- a/apps/external/ajax/seturls.php +++ /dev/null @@ -1,24 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or later. - * See the COPYING-README file. - */ - -require_once('../../../lib/base.php'); -OC_Util::checkAdminUser(); - -if(isset($_POST['s1name'])) OC_Appconfig::setValue( 'external','site1name', $_POST['s1name'] ); -if(isset($_POST['s1url'])) OC_Appconfig::setValue( 'external','site1url', $_POST['s1url'] ); -if(isset($_POST['s2name'])) OC_Appconfig::setValue( 'external','site2name', $_POST['s2name'] ); -if(isset($_POST['s2url'])) OC_Appconfig::setValue( 'external','site2url', $_POST['s2url'] ); -if(isset($_POST['s3name'])) OC_Appconfig::setValue( 'external','site3name', $_POST['s3name'] ); -if(isset($_POST['s3url'])) OC_Appconfig::setValue( 'external','site3url', $_POST['s3url'] ); -if(isset($_POST['s4name'])) OC_Appconfig::setValue( 'external','site4name', $_POST['s4name'] ); -if(isset($_POST['s4url'])) OC_Appconfig::setValue( 'external','site4url', $_POST['s4url'] ); -if(isset($_POST['s5name'])) OC_Appconfig::setValue( 'external','site5name', $_POST['s5name'] ); -if(isset($_POST['s5url'])) OC_Appconfig::setValue( 'external','site5url', $_POST['s5url'] ); - -echo 'true'; - -?> diff --git a/apps/external/appinfo/app.php b/apps/external/appinfo/app.php index 0f536cbf41..74e6d5c94c 100644 --- a/apps/external/appinfo/app.php +++ b/apps/external/appinfo/app.php @@ -1,37 +1,35 @@ . -* -*/ + * ownCloud - External plugin + * + * @author Frank Karlitschek + * @copyright 2011 Frank Karlitschek karlitschek@kde.org + * + * 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 Lesser General Public + * License along with this library. If not, see . + * + */ -OC_APP::registerAdmin('external','settings'); +OC::$CLASSPATH['OC_External'] = 'apps/external/lib/external.php'; +OC_Util::addStyle( 'external', 'style'); -OC_App::register( array( 'order' => 70, 'id' => 'external', 'name' => 'External' )); +OC_APP::registerAdmin('external', 'settings'); -if(OC_Appconfig::getValue( "external","site1name", '' )<>'') OC_App::addNavigationEntry( array( 'id' => 'external_index1', 'order' => 80, 'href' => OC_Helper::linkTo( 'external', 'index.php' ).'?id=1', 'icon' => OC_Helper::imagePath( 'external', 'external.png' ), 'name' => OC_Appconfig::getValue( "external","site1name", '' ))); - -if(OC_Appconfig::getValue( "external","site2name", '' )<>'') OC_App::addNavigationEntry( array( 'id' => 'external_index2', 'order' => 80, 'href' => OC_Helper::linkTo( 'external', 'index.php' ).'?id=2', 'icon' => OC_Helper::imagePath( 'external', 'external.png' ), 'name' => OC_Appconfig::getValue( "external","site2name", '' ))); - -if(OC_Appconfig::getValue( "external","site3name", '' )<>'') OC_App::addNavigationEntry( array( 'id' => 'external_index3', 'order' => 80, 'href' => OC_Helper::linkTo( 'external', 'index.php' ).'?id=3', 'icon' => OC_Helper::imagePath( 'external', 'external.png' ), 'name' => OC_Appconfig::getValue( "external","site3name", '' ))); - -if(OC_Appconfig::getValue( "external","site4name", '' )<>'') OC_App::addNavigationEntry( array( 'id' => 'external_index4', 'order' => 80, 'href' => OC_Helper::linkTo( 'external', 'index.php' ).'?id=4', 'icon' => OC_Helper::imagePath( 'external', 'external.png' ), 'name' => OC_Appconfig::getValue( "external","site4name", '' ))); - -if(OC_Appconfig::getValue( "external","site5name", '' )<>'') OC_App::addNavigationEntry( array( 'id' => 'external_index5', 'order' => 80, 'href' => OC_Helper::linkTo( 'external', 'index.php' ).'?id=5', 'icon' => OC_Helper::imagePath( 'external', 'external.png' ), 'name' => OC_Appconfig::getValue( "external","site5name", '' ))); +OC_App::register(array('order' => 70, 'id' => 'external', 'name' => 'External')); +$sites = OC_External::getSites(); +for ($i = 0; $i < sizeof($sites); $i++) { + OC_App::addNavigationEntry( + array('id' => 'external_index' . ($i + 1), 'order' => 80 + $i, 'href' => OC_Helper::linkTo('external', 'index.php') . '?id=' . ($i + 1), 'icon' => OC_Helper::imagePath('external', 'external.png'), 'name' => $sites[$i][0])); +} \ No newline at end of file diff --git a/apps/external/css/style.css b/apps/external/css/style.css new file mode 100644 index 0000000000..f891cb4bc5 --- /dev/null +++ b/apps/external/css/style.css @@ -0,0 +1,14 @@ +/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- / +/* vim: set shiftwidth=4 tabstop=8 autoindent cindent expandtab: */ + +.site_url { + width: 250px; +} + +.delete_button { + display: none; +} + +.external_sites { + width: 450px; +} diff --git a/apps/external/index.php b/apps/external/index.php index 51cdc344bb..1c20f59eaf 100644 --- a/apps/external/index.php +++ b/apps/external/index.php @@ -1,42 +1,43 @@ . -* -*/ - + * ownCloud - External plugin + * + * @author Frank Karlitschek + * @copyright 2011 Frank Karlitschek karlitschek@kde.org + * + * 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 Lesser General Public + * License along with this library. If not, see . + * + */ require_once('../../lib/base.php'); +require_once('lib/external.php'); OC_Util::checkLoggedIn(); -if(isset($_GET['id'])){ +if (isset($_GET['id'])) { - $id=$_GET['id']; + $id = $_GET['id']; $id = (int) $id; - $url=OC_Appconfig::getValue( "external","site".$id."url", '' ); - OC_App::setActiveNavigationEntry( 'external_index'.$id ); - - $tmpl = new OC_Template( 'external', 'frame', 'user' ); - $tmpl->assign('url',$url); - $tmpl->printPage(); + $sites = OC_External::getSites(); + if (sizeof($sites) >= $id) { + $url = $sites[$id - 1][1]; + OC_App::setActiveNavigationEntry('external_index' . $id); + $tmpl = new OC_Template('external', 'frame', 'user'); + $tmpl->assign('url', $url); + $tmpl->printPage(); + } } - ?> diff --git a/apps/external/js/admin.js b/apps/external/js/admin.js index 6b9b6c6773..0caaabd0b9 100644 --- a/apps/external/js/admin.js +++ b/apps/external/js/admin.js @@ -1,68 +1,57 @@ $(document).ready(function(){ + newSiteHtml = '
    • \n\ + \n\ +
    • '; - - - $('#s1name').blur(function(event){ + // Handler functions + function addSiteEventHandler(event) { event.preventDefault(); - var post = $( "#s1name" ).serialize(); - $.post( OC.filePath('external','ajax','seturls.php') , post, function(data){ OC.msg.finishedSaving('#s1name .msg', data); }); - }); + + saveSites(); + } - $('#s2name').blur(function(event){ + function deleteButtonEventHandler(event) { event.preventDefault(); - var post = $( "#s2name" ).serialize(); - $.post( OC.filePath('external','ajax','seturls.php') , post, function(data){ OC.msg.finishedSaving('#s2name .msg', data); }); - }); - $('#s3name').blur(function(event){ + $(this).tipsy('hide'); + $(this).parent().remove(); + + saveSites(); + } + + function saveSites() { + var post = $('#external').serialize(); + $.post( OC.filePath('external','ajax','setsites.php') , post, function(data) { + // OC.msg.finishedSaving('#site_name .msg', data); + }); + } + + function showDeleteButton(event) { + $(this).find('img.delete_button').fadeIn(100); + } + + function hideDeleteButton(event) { + $(this).find('img.delete_button').fadeOut(100); + } + + // Initialize events + $('input[name^=site_]').change(addSiteEventHandler); + $('img.delete_button').click(deleteButtonEventHandler); + $('img.delete_button').tipsy(); + + $('#external li').hover(showDeleteButton, hideDeleteButton); + + $('#add_external_site').click(function(event) { event.preventDefault(); - var post = $( "#s3name" ).serialize(); - $.post( OC.filePath('external','ajax','seturls.php') , post, function(data){ OC.msg.finishedSaving('#s3name .msg', data); }); - }); + $('#external ul').append(newSiteHtml); - $('#s4name').blur(function(event){ - event.preventDefault(); - var post = $( "#s4name" ).serialize(); - $.post( OC.filePath('external','ajax','seturls.php') , post, function(data){ OC.msg.finishedSaving('#s4name .msg', data); }); + $('input.site_url:last').prev('input.site_name').andSelf().change(addSiteEventHandler); + $('img.delete_button').click(deleteButtonEventHandler); + $('img.delete_button:last').tipsy(); + $('#external li:last').hover(showDeleteButton, hideDeleteButton); + }); - $('#s5name').blur(function(event){ - event.preventDefault(); - var post = $( "#s5name" ).serialize(); - $.post( OC.filePath('external','ajax','seturls.php') , post, function(data){ OC.msg.finishedSaving('#s5name .msg', data); }); - }); - - $('#s1url').blur(function(event){ - event.preventDefault(); - var post = $( "#s1url" ).serialize(); - $.post( OC.filePath('external','ajax','seturls.php') , post, function(data){ OC.msg.finishedSaving('#s1url .msg', data); }); - }); - - $('#s2url').blur(function(event){ - event.preventDefault(); - var post = $( "#s2url" ).serialize(); - $.post( OC.filePath('external','ajax','seturls.php') , post, function(data){ OC.msg.finishedSaving('#s2url .msg', data); }); - }); - - $('#s3url').blur(function(event){ - event.preventDefault(); - var post = $( "#s3url" ).serialize(); - $.post( OC.filePath('external','ajax','seturls.php') , post, function(data){ OC.msg.finishedSaving('#s3url .msg', data); }); - }); - - $('#s4url').blur(function(event){ - event.preventDefault(); - var post = $( "#s4url" ).serialize(); - $.post( OC.filePath('external','ajax','seturls.php') , post, function(data){ OC.msg.finishedSaving('#s4url .msg', data); }); - }); - - $('#s5url').blur(function(event){ - event.preventDefault(); - var post = $( "#s5url" ).serialize(); - $.post( OC.filePath('external','ajax','seturls.php') , post, function(data){ OC.msg.finishedSaving('#s5url .msg', data); }); - }); - - }); diff --git a/apps/external/lib/external.php b/apps/external/lib/external.php new file mode 100644 index 0000000000..9dd3232113 --- /dev/null +++ b/apps/external/lib/external.php @@ -0,0 +1,36 @@ +. + * + */ + +class OC_External { + + public static function getSites() { + if (($sites = json_decode(OC_Appconfig::getValue("external", "sites", ''))) != NULL) { + return $sites; + } + + return array(); + } + +} + +?> diff --git a/apps/external/settings.php b/apps/external/settings.php index 3e0c342512..416c9a5c11 100644 --- a/apps/external/settings.php +++ b/apps/external/settings.php @@ -6,17 +6,5 @@ OC_Util::addScript( "external", "admin" ); $tmpl = new OC_Template( 'external', 'settings'); - $tmpl->assign('s1name',OC_Appconfig::getValue( "external","site1name", '' )); - $tmpl->assign('s2name',OC_Appconfig::getValue( "external","site2name", '' )); - $tmpl->assign('s3name',OC_Appconfig::getValue( "external","site3name", '' )); - $tmpl->assign('s4name',OC_Appconfig::getValue( "external","site4name", '' )); - $tmpl->assign('s5name',OC_Appconfig::getValue( "external","site5name", '' )); - - $tmpl->assign('s1url',OC_Appconfig::getValue( "external","site1url", '' )); - $tmpl->assign('s2url',OC_Appconfig::getValue( "external","site2url", '' )); - $tmpl->assign('s3url',OC_Appconfig::getValue( "external","site3url", '' )); - $tmpl->assign('s4url',OC_Appconfig::getValue( "external","site4url", '' )); - $tmpl->assign('s5url',OC_Appconfig::getValue( "external","site5url", '' )); - return $tmpl->fetchPage(); ?> diff --git a/apps/external/templates/settings.php b/apps/external/templates/settings.php index a72327d35c..a130477d46 100644 --- a/apps/external/templates/settings.php +++ b/apps/external/templates/settings.php @@ -1,23 +1,21 @@
      External Sites
      - - -
      - - -
      - - -
      - - -
      - - -
      +
        + + + + '; + } + ?> - +
      + + +
      From 9f015337102193ae7cff59b47c577f15c05259c4 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Wed, 7 Mar 2012 15:44:46 +0100 Subject: [PATCH 028/132] fix for webdav when having additional storage backends mounted --- lib/connector/sabre/directory.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/connector/sabre/directory.php b/lib/connector/sabre/directory.php index bb03851e39..cc37bf22d5 100644 --- a/lib/connector/sabre/directory.php +++ b/lib/connector/sabre/directory.php @@ -73,8 +73,8 @@ class OC_Connector_Sabre_Directory extends OC_Connector_Sabre_Node implements Sa $nodes = array(); // foreach(scandir($this->path) as $node) if($node!='.' && $node!='..') $nodes[] = $this->getChild($node); - if( OC_Filesystem::is_dir($this->path)){ - $dh = OC_Filesystem::opendir($this->path); + if( OC_Filesystem::is_dir($this->path . '/')){ + $dh = OC_Filesystem::opendir($this->path . '/'); while(( $node = readdir($dh)) !== false ){ if($node!='.' && $node!='..'){ $nodes[] = $this->getChild($node); From a4543175cea05373906ce7f9507af597a78c5dc4 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Wed, 7 Mar 2012 16:24:49 +0100 Subject: [PATCH 029/132] make gallary work with archives --- apps/gallery/ajax/galleryOp.php | 1 - apps/gallery/lib/scanner.php | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/gallery/ajax/galleryOp.php b/apps/gallery/ajax/galleryOp.php index ee919daeac..74ac905d07 100644 --- a/apps/gallery/ajax/galleryOp.php +++ b/apps/gallery/ajax/galleryOp.php @@ -95,7 +95,6 @@ function handleGetGallery($path) { else $path = '/'.ltrim($path, '/'); if (strlen($path) > 1) $path = rtrim($path, '/'); - error_log($path); $result = OC_Gallery_Album::find(OC_User::getUser(), null, $path); $album_details = $result->fetchRow(); diff --git a/apps/gallery/lib/scanner.php b/apps/gallery/lib/scanner.php index 8dcd77821c..1e8fdb63fb 100644 --- a/apps/gallery/lib/scanner.php +++ b/apps/gallery/lib/scanner.php @@ -47,7 +47,7 @@ class OC_Gallery_Scanner { $current_album = array('name'=> $path, 'imagesCount' => 0, 'images' => array()); $current_album['name'] = self::createName($current_album['name']); - if ($dh = OC_Filesystem::opendir($path)) { + if ($dh = OC_Filesystem::opendir($path.'/')) { while (($filename = readdir($dh)) !== false) { $filepath = ($path[strlen($path)-1]=='/'?$path:$path.'/').$filename; if (substr($filename, 0, 1) == '.') continue; From 41817db2e2fb657a9efad5b8924fd059e98524e5 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Wed, 7 Mar 2012 16:27:51 +0100 Subject: [PATCH 030/132] no rounded borders for album decoration --- apps/gallery/css/styles.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/gallery/css/styles.css b/apps/gallery/css/styles.css index 1bff610c78..013cd1b262 100644 --- a/apps/gallery/css/styles.css +++ b/apps/gallery/css/styles.css @@ -3,7 +3,7 @@ div#gallery_list.leftcontent { padding-top: 15pt; margin: 0; position: absolute; div.gallery_box { width: 200px; position:relative; text-align: center; border: 0; display: inline-block; margin: 5pt; vertical-align: top; padding: 5px 5px 5px 5px; position: relative; -webkit-transition: color 0.5s ease-in-out; -o-transition: color 0.5s ease-in-out; -moz-transition: color 0.5s ease-in-out;color: #BBB;} div.album {border: 1px solid #e0e0e0; border-radius: 7px;} div.gallery_box h1 { font-size: 9pt; font-family: Verdana; } -div.gallery_album_decoration { width: 200px; position: absolute; border: 0; height: 20px; top: 5px; text-align:right; vertical-align:middle; background-color: #eee; opacity: 0; -webkit-transition: opacity 0.5s ease-in-out; -moz-transition: opacity 0.5s ease-in-out; -o-transition: opacity 0.5s ease-in-out; border-bottom-right-radius: 7px; border-bottom-left-radius: 7px; -moz-border-radius-bottomright: 7px; -moz-border-radius-bottomleft:7px;} +div.gallery_album_decoration { width: 200px; position: absolute; border: 0; height: 20px; top: 5px; text-align:right; vertical-align:middle; background-color: #eee; opacity: 0; -webkit-transition: opacity 0.5s ease-in-out; -moz-transition: opacity 0.5s ease-in-out; -o-transition: opacity 0.5s ease-in-out; } div.gallery_box:hover { color: black; } div.gallery_box:hover div.gallery_album_decoration { opacity: 0.7;} div.gallery_album_decoration a {padding: 0 4pt; cursor: pointer;} From 1d88ab57ec31c33e2edcd2bd7e54868927e999e0 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Wed, 7 Mar 2012 16:28:57 +0100 Subject: [PATCH 031/132] dont open the album when clicking the remove/rename button --- apps/gallery/js/albums.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/gallery/js/albums.js b/apps/gallery/js/albums.js index c12cbacf5b..3882deb514 100644 --- a/apps/gallery/js/albums.js +++ b/apps/gallery/js/albums.js @@ -50,10 +50,12 @@ Albums={ local.attr('data-album',a.name); $(".gallery_album_decoration a.rename", local).bind('click', {name: a.name},function(event){ event.preventDefault(); + event.stopPropagation(); galleryRename(event.data.name); }); $(".gallery_album_decoration a.remove", local).bind('click', {name: a.name},function(event){ event.preventDefault(); + event.stopPropagation(); galleryRemove(event.data.name); }); // $("a.view", local).attr('href','?view='+decodeURIComponent(escape(a.name))); From 75323b86d157c48031b9ac8c151e4a41577a1481 Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Wed, 7 Mar 2012 16:39:56 +0100 Subject: [PATCH 032/132] Contacts: UI updates and ajax methods for categories. --- apps/contacts/ajax/addproperty.php | 15 +- apps/contacts/ajax/categories/add.php | 39 +++ apps/contacts/ajax/categories/checksumfor.php | 28 ++ apps/contacts/ajax/categories/delete.php | 60 ++++ apps/contacts/ajax/categories/edit.php | 28 ++ apps/contacts/ajax/categories/list.php | 17 + apps/contacts/ajax/contactdetails.php | 2 +- apps/contacts/ajax/saveproperty.php | 32 +- apps/contacts/css/contacts.css | 15 +- apps/contacts/index.php | 2 + apps/contacts/js/contacts.js | 311 +++++++++++++++--- apps/contacts/lib/vcard.php | 65 +++- apps/contacts/templates/part.contact.php | 14 +- lib/vcategories.php | 66 ++-- 14 files changed, 593 insertions(+), 101 deletions(-) create mode 100644 apps/contacts/ajax/categories/add.php create mode 100644 apps/contacts/ajax/categories/checksumfor.php create mode 100644 apps/contacts/ajax/categories/delete.php create mode 100644 apps/contacts/ajax/categories/edit.php create mode 100644 apps/contacts/ajax/categories/list.php diff --git a/apps/contacts/ajax/addproperty.php b/apps/contacts/ajax/addproperty.php index 028974e1c6..a28aed34d2 100644 --- a/apps/contacts/ajax/addproperty.php +++ b/apps/contacts/ajax/addproperty.php @@ -27,14 +27,16 @@ require_once('../../../lib/base.php'); OC_JSON::checkLoggedIn(); OC_JSON::checkAppEnabled('contacts'); -$id = $_POST['id']; -$vcard = OC_Contacts_App::getContactVCard( $id ); +$id = isset($_POST['id'])?$_POST['id']:null; +$name = isset($_POST['name'])?$_POST['name']:null; +$value = isset($_POST['value'])?$_POST['value']:null; +$parameters = isset($_POST['parameters'])?$_POST['parameters']:array(); + +$vcard = OC_Contacts_App::getContactVCard($id); -$name = $_POST['name']; -$value = $_POST['value']; if(!is_array($value)){ $value = trim($value); - if(!$value && in_array($name, array('TEL', 'EMAIL', 'ORG', 'BDAY', 'NICKNAME'))) { + if(!$value && in_array($name, array('TEL', 'EMAIL', 'ORG', 'BDAY', 'NICKNAME', 'NOTE'))) { OC_JSON::error(array('data' => array('message' => OC_Contacts_App::$l10n->t('Cannot add empty property.')))); exit(); } @@ -51,7 +53,6 @@ if(!is_array($value)){ exit(); } } -$parameters = isset($_POST['parameters']) ? $_POST['parameters'] : array(); // Prevent setting a duplicate entry $current = $vcard->select($name); @@ -82,7 +83,9 @@ switch($name) { } case 'N': case 'ORG': + case 'NOTE': case 'NICKNAME': + // TODO: Escape commas and semicolons. break; case 'EMAIL': $value = strtolower($value); diff --git a/apps/contacts/ajax/categories/add.php b/apps/contacts/ajax/categories/add.php new file mode 100644 index 0000000000..9b6c262978 --- /dev/null +++ b/apps/contacts/ajax/categories/add.php @@ -0,0 +1,39 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +require_once('../../../../lib/base.php'); +OC_JSON::checkLoggedIn(); +OC_JSON::checkAppEnabled('contacts'); + +function bailOut($msg) { + OC_JSON::error(array('data' => array('message' => $msg))); + OC_Log::write('contacts','ajax/categories/add.php: '.$msg, OC_Log::DEBUG); + exit(); +} +function debug($msg) { + OC_Log::write('contacts','ajax/categories/add.php: '.$msg, OC_Log::DEBUG); +} + +$category = isset($_GET['category'])?strip_tags($_GET['category']):null; + +if(is_null($category)) { + bailOut(OC_Contacts_App::$l10n->t('No category to add?')); +} + +debug(print_r($category, true)); + +$categories = new OC_VCategories('contacts'); +if($categories->hasCategory($category)) { + bailOut(OC_Contacts_App::$l10n->t('This category already exists: '.$category)); +} else { + $categories->add($category, true); +} + +OC_JSON::success(array('data' => array('categories'=>$categories->categories()))); + +?> diff --git a/apps/contacts/ajax/categories/checksumfor.php b/apps/contacts/ajax/categories/checksumfor.php new file mode 100644 index 0000000000..ff535866bf --- /dev/null +++ b/apps/contacts/ajax/categories/checksumfor.php @@ -0,0 +1,28 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +require_once('../../../../lib/base.php'); +OC_JSON::checkLoggedIn(); +OC_JSON::checkAppEnabled('contacts'); + +$id = isset($_GET['id'])?$_GET['id']:null; +if(is_null($id)) { + OC_JSON::error(array('data' => array('message' => OC_Contacts_App::$l10n->t('No ID provided')))); + exit(); +} +$vcard = OC_Contacts_App::getContactVCard( $id ); +foreach($vcard->children as $property){ + //OC_Log::write('contacts','ajax/categories/checksumfor.php: '.$property->name, OC_Log::DEBUG); + if($property->name == 'CATEGORIES') { + $checksum = md5($property->serialize()); + OC_JSON::success(array('data' => array('checksum'=>$checksum))); + exit(); + } +} +OC_JSON::error(array('data' => array('message' => OC_Contacts_App::$l10n->t('Error setting checksum.')))); +?> diff --git a/apps/contacts/ajax/categories/delete.php b/apps/contacts/ajax/categories/delete.php new file mode 100644 index 0000000000..3ba5aa1606 --- /dev/null +++ b/apps/contacts/ajax/categories/delete.php @@ -0,0 +1,60 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +require_once('../../../../lib/base.php'); +OC_JSON::checkLoggedIn(); +OC_JSON::checkAppEnabled('contacts'); + +foreach ($_POST as $key=>$element) { + debug('_POST: '.$key.'=>'.print_r($element, true)); +} + +function bailOut($msg) { + OC_JSON::error(array('data' => array('message' => $msg))); + OC_Log::write('contacts','ajax/categories/delete.php: '.$msg, OC_Log::DEBUG); + exit(); +} +function debug($msg) { + OC_Log::write('contacts','ajax/categories/delete.php: '.$msg, OC_Log::DEBUG); +} + +$categories = isset($_POST['categories'])?$_POST['categories']:null; + +if(is_null($categories)) { + bailOut(OC_Contacts_App::$l10n->t('No categories selected for deletion.')); +} + +debug(print_r($categories, true)); + +$addressbooks = OC_Contacts_Addressbook::all(OC_User::getUser()); +if(count($addressbooks) == 0) { + bailOut(OC_Contacts_App::$l10n->t('No address books found.')); +} +$addressbookids = array(); +foreach($addressbooks as $addressbook) { + $addressbookids[] = $addressbook['id']; +} +$contacts = OC_Contacts_VCard::all($addressbookids); +if(count($contacts) == 0) { + bailOut(OC_Contacts_App::$l10n->t('No contacts found.')); +} + +$cards = array(); +foreach($contacts as $contact) { + $cards[] = array($contact['id'], $contact['carddata']); +} + +debug('Before delete: '.print_r($categories, true)); + +$catman = new OC_VCategories('contacts'); +$catman->delete($categories, $cards); +debug('After delete: '.print_r($catman->categories(), true)); +OC_Contacts_VCard::updateDataByID($cards); +OC_JSON::success(array('data' => array('categories'=>$catman->categories()))); + +?> diff --git a/apps/contacts/ajax/categories/edit.php b/apps/contacts/ajax/categories/edit.php new file mode 100644 index 0000000000..8ecc3540b1 --- /dev/null +++ b/apps/contacts/ajax/categories/edit.php @@ -0,0 +1,28 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +require_once('../../../../lib/base.php'); +OC_JSON::checkLoggedIn(); +OC_JSON::checkAppEnabled('contacts'); +function bailOut($msg) { + OC_JSON::error(array('data' => array('message' => $msg))); + OC_Log::write('contacts','ajax/categories/edit.php: '.$msg, OC_Log::DEBUG); + exit(); +} +function debug($msg) { + OC_Log::write('contacts','ajax/categories/edit.php: '.$msg, OC_Log::DEBUG); +} + +$tmpl = new OC_TEMPLATE("contacts", "part.edit_categories_dialog"); + +$categories = OC_Contacts_App::$categories->categories(); +debug(print_r($categories, true)); +$tmpl->assign('categories',$categories); +$tmpl->printpage(); + +?> diff --git a/apps/contacts/ajax/categories/list.php b/apps/contacts/ajax/categories/list.php new file mode 100644 index 0000000000..3b41b7bfa9 --- /dev/null +++ b/apps/contacts/ajax/categories/list.php @@ -0,0 +1,17 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +require_once('../../../../lib/base.php'); +OC_JSON::checkLoggedIn(); +OC_JSON::checkAppEnabled('contacts'); + +$categories = OC_Contacts_App::$categories->categories(); + +OC_JSON::success(array('data' => array('categories'=>$categories))); + +?> diff --git a/apps/contacts/ajax/contactdetails.php b/apps/contacts/ajax/contactdetails.php index f35fd595c5..03895c862a 100644 --- a/apps/contacts/ajax/contactdetails.php +++ b/apps/contacts/ajax/contactdetails.php @@ -71,5 +71,5 @@ if(isset($details['PHOTO'])) { $details['PHOTO'] = false; } $details['id'] = $id; - +OC_Contacts_App::setLastModifiedHeader($vcard); OC_JSON::success(array('data' => $details)); diff --git a/apps/contacts/ajax/saveproperty.php b/apps/contacts/ajax/saveproperty.php index 6f8366243f..e31c4b7c23 100644 --- a/apps/contacts/ajax/saveproperty.php +++ b/apps/contacts/ajax/saveproperty.php @@ -36,7 +36,7 @@ function debug($msg) { OC_Log::write('contacts','ajax/saveproperty.php: '.$msg, OC_Log::DEBUG); } foreach ($_POST as $key=>$element) { - debug('_POST: '.$key.'=>'.$element); + debug('_POST: '.$key.'=>'.print_r($element, true)); } $id = isset($_POST['id'])?$_POST['id']:null; @@ -51,12 +51,8 @@ $checksum = isset($_POST['checksum'])?$_POST['checksum']:null; // } // } -if(is_array($value)){ - $value = array_map('strip_tags', $value); - ksort($value); // NOTE: Important, otherwise the compound value will be set in the order the fields appear in the form! - $value = OC_VObject::escapeSemicolons($value); -} else { - $value = trim(strip_tags($value)); +if(!$name) { + bailOut(OC_Contacts_App::$l10n->t('element name is not set.')); } if(!$id) { bailOut(OC_Contacts_App::$l10n->t('id is not set.')); @@ -64,14 +60,22 @@ if(!$id) { if(!$checksum) { bailOut(OC_Contacts_App::$l10n->t('checksum is not set.')); } -if(!$name) { - bailOut(OC_Contacts_App::$l10n->t('element name is not set.')); +if(is_array($value)){ + $value = array_map('strip_tags', $value); + ksort($value); // NOTE: Important, otherwise the compound value will be set in the order the fields appear in the form! + if($name == 'CATEGORIES') { + $value = OC_Contacts_VCard::escapeDelimiters($value, ','); + } else { + $value = OC_Contacts_VCard::escapeDelimiters($value, ';'); + } +} else { + $value = trim(strip_tags($value)); } $vcard = OC_Contacts_App::getContactVCard( $id ); $line = OC_Contacts_App::getPropertyLineByChecksum($vcard, $checksum); if(is_null($line)) { - bailOut(OC_Contacts_App::$l10n->t('Information about vCard is incorrect. Please reload the page.'.$checksum.' "'.$line.'"')); + bailOut(OC_Contacts_App::$l10n->t('Information about vCard is incorrect. Please reload the page: ').$checksum); } $element = $vcard->children[$line]->name; @@ -91,7 +95,9 @@ switch($element) { } case 'N': case 'ORG': + case 'NOTE': case 'NICKNAME': + case 'CATEGORIES': debug('Setting string:'.$name.' '.$value); $vcard->setString($name, $value); break; @@ -123,12 +129,8 @@ $checksum = md5($vcard->children[$line]->serialize()); debug('New checksum: '.$checksum); if(!OC_Contacts_VCard::edit($id,$vcard->serialize())) { - OC_JSON::error(array('data' => array('message' => OC_Contacts_App::$l10n->t('Error updating contact property.')))); - OC_Log::write('contacts','ajax/setproperty.php: Error updating contact property: '.$value, OC_Log::ERROR); + bailOut(OC_Contacts_App::$l10n->t('Error updating contact property.')); exit(); } -//$adr_types = OC_Contacts_App::getTypesOfProperty('ADR'); -//$phone_types = OC_Contacts_App::getTypesOfProperty('TEL'); - OC_JSON::success(array('data' => array( 'line' => $line, 'checksum' => $checksum, 'oldchecksum' => $_POST['checksum'] ))); diff --git a/apps/contacts/css/contacts.css b/apps/contacts/css/contacts.css index 384541f375..65a6eb2480 100644 --- a/apps/contacts/css/contacts.css +++ b/apps/contacts/css/contacts.css @@ -20,7 +20,8 @@ #firstrun { /*border: thin solid lightgray;*/ width: 80%; margin: 5em auto auto auto; text-align: center; font-weight:bold; font-size:1.5em; color:#777;} #firstrun #selections { /*border: thin solid lightgray;*/ font-size:0.8em; width: 100%; margin: 2em auto auto auto; clear: both; } -#card input[type="text"].contacts_property,input[type="email"].contacts_property { width: 16em; } +#card input[type="text"].contacts_property,input[type="email"].contacts_property { width: 14em; } +.categories { float: left; width: 16em; } #card input[type="text"],input[type="email"],input[type="tel"],input[type="date"], select { background-color: #f8f8f8; border: 0 !important; -webkit-appearance:none !important; -moz-appearance:none !important; -webkit-box-sizing:none !important; -moz-box-sizing:none !important; box-sizing:none !important; -moz-box-shadow: none; -webkit-box-shadow: none; box-shadow: none; -moz-border-radius: 0px; -webkit-border-radius: 0px; border-radius: 0px; float: left; } #card input[type="text"]:hover, input[type="text"]:focus, input[type="text"]:active,input[type="email"]:hover,input[type="tel"]:hover,input[type="date"]:hover,input[type="date"],input[type="date"]:hover,input[type="date"]:active,input[type="date"]:active,input[type="date"]:active,input[type="email"]:active,input[type="tel"]:active, select:hover, select:focus, select:active { border: 0 !important; -webkit-appearance:textfield; -moz-appearance:textfield; -webkit-box-sizing:content-box; -moz-box-sizing:content-box; box-sizing:content-box; background:#fff; color:#333; border:1px solid #ddd; -moz-box-shadow:0 1px 1px #fff, 0 2px 0 #bbb inset; -webkit-box-shadow:0 1px 1px #fff, 0 1px 0 #bbb inset; box-shadow:0 1px 1px #fff, 0 1px 0 #bbb inset; -moz-border-radius:.5em; -webkit-border-radius:.5em; border-radius:.5em; outline:none; float: left; } input[type="text"]:invalid,input[type="email"]:invalid,input[type="tel"]:invalid,input[type="date"]:invalid { background-color: #ffc0c0 !important; } @@ -68,7 +69,7 @@ dl.form /*background-color: yellow;*/ } -.loading { background: url('../../../core/img/loading.gif') no-repeat center !important;} +.loading { background: url('../../../core/img/loading.gif') no-repeat center !important; /*cursor: progress; */ cursor: wait; } /*.add { cursor: pointer; width: 25px; height: 25px; margin: 0px; float: right; position:relative; content: "\+"; font-weight: bold; color: #666; font-size: large; bottom: 0px; right: 0px; clear: both; text-align: center; vertical-align: bottom; display: none; }*/ @@ -185,4 +186,12 @@ 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; } + +#categoryform .scrollarea { position: absolute; left: 10px; top: 10px; right: 10px; bottom: 50px; overflow: auto; border:1px solid #ddd; background: #f8f8f8; } +#categoryform .bottombuttons { position: absolute; bottom: 10px;} +#categoryform .bottombuttons * { float: left;} +/*#categorylist { border:1px solid #ddd;}*/ +#categorylist li { background:#f8f8f8; padding:.3em .8em; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; -webkit-transition:background-color 500ms; -moz-transition:background-color 500ms; -o-transition:background-color 500ms; transition:background-color 500ms; } +#categorylist li:hover, li:active { background:#eee; } +#category_addinput { width: 10em; } \ No newline at end of file diff --git a/apps/contacts/index.php b/apps/contacts/index.php index 0a21ddd04b..a7817d35e5 100644 --- a/apps/contacts/index.php +++ b/apps/contacts/index.php @@ -34,6 +34,7 @@ if(!is_null($id)) { } $property_types = OC_Contacts_App::getAddPropertyOptions(); $phone_types = OC_Contacts_App::getTypesOfProperty('TEL'); +$categories = OC_Contacts_App::$categories->categories(); $upload_max_filesize = OC_Helper::computerFileSize(ini_get('upload_max_filesize')); $post_max_size = OC_Helper::computerFileSize(ini_get('post_max_size')); @@ -59,6 +60,7 @@ $tmpl->assign('uploadMaxFilesize', $maxUploadFilesize); $tmpl->assign('uploadMaxHumanFilesize', OC_Helper::humanFileSize($maxUploadFilesize)); $tmpl->assign('property_types',$property_types); $tmpl->assign('phone_types',$phone_types); +$tmpl->assign('categories',$categories); $tmpl->assign('addressbooks', $addressbooks); $tmpl->assign('contacts', $contacts); $tmpl->assign('details', $details ); diff --git a/apps/contacts/js/contacts.js b/apps/contacts/js/contacts.js index 11661320c5..7306e5714c 100644 --- a/apps/contacts/js/contacts.js +++ b/apps/contacts/js/contacts.js @@ -4,13 +4,105 @@ function ucwords (str) { }); } -String.prototype.strip_tags = function(){ - tags = this; - stripped = tags.replace(/[\<\>]/gi, ""); - return stripped; +Categories={ + edit:function(){ + console.log('Categories.edit'); + $('body').append('
      '); + $('#category_dialog').load(OC.filePath('contacts', 'ajax', 'categories/edit.php'), function(response, status, xhr){ + try { + var response = jQuery.parseJSON(response); + console.log('status: ' + status + ', response: ' + response + ', response.status:' + response.status); + if(response.status == 'error'){ + alert(response.data.message); + } else { + alert(response); + } + } catch(e) { + $('#edit_categories_dialog').dialog({ + modal: true, + height: 350, minHeight:200, width: 250, minWidth: 200, + buttons: { + 'Delete':function() { + Categories.delete(); + }, + 'Rescan':function() { + Categories.rescan(); + } + }, + close : function(event, ui) { + //alert('close'); + $(this).dialog('destroy').remove(); + $('#category_dialog').remove(); + }, + open : function(event, ui) { + $('#category_addinput').live('input',function(){ + if($(this).val().length > 0) { + $('#category_addbutton').removeAttr('disabled'); + } + }); + $('#categoryform').submit(function() { + Categories.add($('#category_addinput').val()); + $('#category_addinput').val(''); + $('#category_addbutton').attr('disabled', 'disabled'); + return false; + }); + $('#category_addbutton').live('click',function(e){ + e.preventDefault(); + if($('#category_addinput').val().length > 0) { + Categories.add($('#category_addinput').val()); + $('#category_addinput').val(''); + } + }); + } + }); + } + }); + }, + delete:function(){ + var categories = $('#categorylist').find('input[type="checkbox"]').serialize(); + console.log('Categories.delete: ' + categories); + $.post(OC.filePath('contacts', 'ajax', 'categories/delete.php'),categories,function(jsondata){ + if(jsondata.status == 'success'){ + Categories._update(jsondata.data.categories); + } else { + alert(jsondata.data.message); + } + }); + }, + add:function(category){ + console.log('Categories.add ' + category); + $.getJSON(OC.filePath('contacts', 'ajax', 'categories/add.php'),{'category':category},function(jsondata){ + if(jsondata.status == 'success'){ + Categories._update(jsondata.data.categories); + } else { + alert(jsondata.data.message); + } + }); + return false; + }, + rescan:function(){ + console.log('Categories.rescan'); + $.getJSON(OC.filePath('contacts', 'ajax', 'categories/rescan.php'),{},function(jsondata){ + if(jsondata.status == 'success'){ + Categories._update(jsondata.data.categories); + } else { + alert(jsondata.data.message); + } + }); + }, + _update:function(categories){ + var categorylist = $('#categorylist'); + categorylist.find('li').remove(); + for(var category in categories) { + var item = '
    • ' + categories[category] + '
    • '; + $(item).appendTo(categorylist); + } + if(Categories.changed != undefined) { + Categories.changed(categories); + } + } } - Contacts={ UI:{ notImplemented:function() { @@ -125,22 +217,26 @@ Contacts={ // NOTE: Do we ever get here? $('#messagebox').dialog('moveToTop'); }else{ - $('#dialog_holder').load(OC.filePath('contacts', 'ajax', 'messagebox.php'), function(){ - $('#messagebox').dialog( - { - autoOpen: true, - title: title, - buttons: [{ - text: "Ok", - click: function() { $(this).dialog("close"); } - }], - close: function(event, ui) { - $(this).dialog('destroy').remove(); - }, - open: function(event, ui) { - $('#messagebox_msg').html(msg); - } - }); + $('#dialog_holder').load(OC.filePath('contacts', 'ajax', 'messagebox.php'), function(jsondata){ + if(jsondata.status != 'error'){ + $('#messagebox').dialog( + { + autoOpen: true, + title: title, + buttons: [{ + text: "Ok", + click: function() { $(this).dialog("close"); } + }], + close: function(event, ui) { + $(this).dialog('destroy').remove(); + }, + open: function(event, ui) { + $('#messagebox_msg').html(msg); + } + }); + } else { + alert(jsondata.data.message); + } }); } }, @@ -182,6 +278,12 @@ Contacts={ $('#bday').datepicker({ dateFormat : 'dd-mm-yy' }); + $('#categories_value').find('select').multiselect({ + noneSelectedText: t('contacts', 'Select categories'), + header: false, + selectedList: 6, + classes: 'categories' + }); // Style phone types $('#phonelist').find('select[class*="contacts_property"]').multiselect({ noneSelectedText: t('contacts', 'Select type'), @@ -361,7 +463,7 @@ Contacts={ this.data = jsondata; this.id = this.data.id; $('#rightcontent').data('id',this.id); - //console.log('loaded: ' + this.data.FN[0]['value']); + console.log('loaded: ' + this.data.FN[0]['value']); this.populateNameFields(); this.loadCategories(); this.loadPhoto(); @@ -369,6 +471,16 @@ Contacts={ this.loadPhones(); this.loadAddresses(); this.loadSingleProperties(); + // TODO: load NOTE ;-) + if(this.data.NOTE) { + $('#note').data('checksum', this.data.NOTE[0]['checksum']); + $('#note').find('textarea').val(this.data.NOTE[0]['value']); + $('#note').show(); + } else { + $('#note').data('checksum', ''); + $('#note').find('textarea').val(''); + $('#note').hide(); + } }, loadSingleProperties:function() { var props = ['BDAY', 'NICKNAME', 'ORG']; @@ -457,21 +569,64 @@ Contacts={ $('#contact_identity').find('*[data-element="FN"]').data('checksum', this.data.FN[0]['checksum']); $('#contact_identity').show(); }, - loadCategories:function(){ + hasCategory:function(category) { if(this.data.CATEGORIES) { - // + for(var c in this.data.CATEGORIES[0]['value']) { + var cat = this.data.CATEGORIES[0]['value'][c]; + //console.log('hasCategory: ' + cat + ' === ' + category + '?'); + if(typeof cat === 'string' && (cat.toUpperCase() === category.toUpperCase())) { + //console.log('Yes'); + return true; + } + } } + return false; + }, + categoriesChanged:function(categories) { // Categories added/deleted. + console.log('categoriesChanged for ' + Contacts.UI.Card.id + ' : ' + categories); + var categorylist = $('#categories_value').find('select'); + categorylist.find('option').remove(); + for(var category in categories) { + console.log('categoriesChanged: ' + categories[category]); + var selected = Contacts.UI.Card.hasCategory(categories[category]) ? ' selected="selected"' : ''; + var item = ''; + $(item).appendTo(categorylist); + } + $('#categories_value').find('select').multiselect('refresh'); + $.getJSON(OC.filePath('contacts', 'ajax', 'categories/checksumfor.php'),{'id':Contacts.UI.Card.id},function(jsondata){ + if(jsondata.status == 'success'){ + console.log('Setting checksum: ' + jsondata.data.checksum); + $('#categories_value').data('checksum', jsondata.data.checksum); + } else { + Contacts.UI.messageBox(t('contacts', 'Error'), jsondata.data.message); + } + }); + }, + loadCategories:function(){ // On loading contact. + var categories = $('#categories_value').find('select'); + if(this.data.CATEGORIES) { + $('#categories_value').data('checksum', this.data.CATEGORIES[0]['checksum']); + } else { + $('#categories_value').data('checksum', ''); + } + categories.find('option').each(function(){ + if(Contacts.UI.Card.hasCategory($(this).val())) { + $(this).attr('selected', 'selected'); + } else { + $(this).removeAttr('selected'); + } + }); + categories.multiselect('refresh'); }, editNew:function(){ // add a new contact this.id = ''; this.fn = ''; this.fullname = ''; this.givname = ''; this.famname = ''; this.addname = ''; this.honpre = ''; this.honsuf = ''; - $.getJSON('ajax/newcontact.php',{},function(jsondata){ + $.getJSON(OC.filePath('contacts', 'ajax', 'newcontact.php'),{},function(jsondata){ if(jsondata.status == 'success'){ id = ''; $('#rightcontent').data('id',''); $('#rightcontent').html(jsondata.data.page); Contacts.UI.Card.editName(); - } - else{ + } else { Contacts.UI.messageBox(t('contacts', 'Error'), jsondata.data.message); //alert(jsondata.data.message); } @@ -479,14 +634,19 @@ Contacts={ }, savePropertyInternal:function(name, fields, oldchecksum, checksum){ // TODO: Add functionality for new fields. - //console.log('savePropertyInternal: ' + name + ', checksum: ' + checksum); - //console.log('savePropertyInternal: ' + this.data[name]); + console.log('savePropertyInternal: ' + name + ', fields: ' + fields + 'checksum: ' + checksum); + console.log('savePropertyInternal: ' + this.data[name]); + var multivalue = ['CATEGORIES']; var params = {}; - var value = undefined; + var value = multivalue.indexOf(name) != -1 ? new Array() : undefined; jQuery.each(fields, function(i, field){ //.substring(11,'parameters[TYPE][]'.indexOf(']')) if(field.name.substring(0, 5) === 'value') { - value = field.value; + if(multivalue.indexOf(name) != -1) { + value.push(field.value); + } else { + value = field.value; + } } else if(field.name.substring(0, 10) === 'parameters') { var p = field.name.substring(11,'parameters[TYPE][]'.indexOf(']')); if(!(p in params)) { @@ -506,7 +666,7 @@ Contacts={ saveProperty:function(obj){ // I couldn't get the selector to filter on 'contacts_property' so I filter by hand here :-/ if(!$(obj).hasClass('contacts_property')) { - //console.log('Filtering out object.' + obj); + console.log('Filtering out object.' + obj); return false; } if($(obj).hasClass('nonempty') && $(obj).val().trim() == '') { @@ -529,32 +689,38 @@ Contacts={ if(checksum != undefined && checksum != '') { // save q = q + '&checksum=' + checksum; console.log('Saving: ' + q); + $(obj).attr('disabled', 'disabled'); $.post('ajax/saveproperty.php',q,function(jsondata){ if(jsondata.status == 'success'){ container.data('checksum', jsondata.data.checksum); Contacts.UI.Card.savePropertyInternal(name, fields, checksum, jsondata.data.checksum); Contacts.UI.loading(container, false); + $(obj).removeAttr('disabled'); return true; } else{ Contacts.UI.messageBox(t('contacts', 'Error'), jsondata.data.message); Contacts.UI.loading(container, false); + $(obj).removeAttr('disabled'); return false; } },'json'); } else { // add console.log('Adding: ' + q); + $(obj).attr('disabled', 'disabled'); $.post('ajax/addproperty.php',q,function(jsondata){ if(jsondata.status == 'success'){ container.data('checksum', jsondata.data.checksum); // TODO: savePropertyInternal doesn't know about new fields //Contacts.UI.Card.savePropertyInternal(name, fields, checksum, jsondata.data.checksum); Contacts.UI.loading(container, false); + $(obj).removeAttr('disabled'); return true; } else{ Contacts.UI.messageBox(t('contacts', 'Error'), jsondata.data.message); Contacts.UI.loading(container, false); + $(obj).removeAttr('disabled'); return false; } },'json'); @@ -565,10 +731,14 @@ Contacts={ console.log('addProperty:' + type); switch (type) { case 'PHOTO': - this.loadPhoto(); + this.loadPhoto(true); $('#file_upload_form').show(); $('#contacts_propertymenu a[data-type="'+type+'"]').parent().hide(); break; + case 'NOTE': + $('#note').show(); + $('#contacts_propertymenu a[data-type="'+type+'"]').parent().hide(); + break; case 'EMAIL': if($('#emaillist>li').length == 1) { $('#emails').show(); @@ -647,8 +817,9 @@ Contacts={ if($('#edit_name_dialog').dialog('isOpen') == true){ $('#edit_name_dialog').dialog('moveToTop'); }else{ // TODO: If id=='' call addcontact.php (or whatever name) instead and reload view with id. - $('#dialog_holder').load(OC.filePath('contacts', 'ajax', 'editname.php')+'?id='+this.id, function(){ - $('#edit_name_dialog' ).dialog({ + $('#dialog_holder').load(OC.filePath('contacts', 'ajax', 'editname.php')+'?id='+this.id, function(jsondata){ + if(jsondata.status != 'error'){ + $('#edit_name_dialog' ).dialog({ modal: (isnew && true || false), closeOnEscape: (isnew == '' && false || true), title: (isnew && t('contacts', 'Add contact') || t('contacts', 'Edit name')), @@ -667,7 +838,10 @@ Contacts={ open : function(event, ui) { // load 'N' property - maybe :-P }*/ - }); + }); + } else { + alert(jsondata.data.message); + } }); } }, @@ -692,7 +866,14 @@ Contacts={ $('#fn_select option').remove(); //$('#fn_select').combobox('value', this.fn); - var names = [this.fullname, this.givname + ' ' + this.famname, this.famname + ' ' + this.givname, this.famname + ', ' + this.givname]; + var tmp = [this.fullname, this.givname + ' ' + this.famname, this.famname + ' ' + this.givname, this.famname + ', ' + this.givname]; + var names = new Array(); + for(var name in tmp) { + console.log('idx: ' + names.indexOf(tmp[name])); + if(names.indexOf(tmp[name]) == -1) { + names.push(tmp[name]); + } + } $.each(names, function(key, value) { $('#fn_select') .append($('') @@ -771,8 +952,9 @@ Contacts={ if($('#edit_address_dialog').dialog('isOpen') == true){ $('#edit_address_dialog').dialog('moveToTop'); }else{ - $('#dialog_holder').load(OC.filePath('contacts', 'ajax', 'editaddress.php')+q, function(){ - $('#edit_address_dialog' ).dialog({ + $('#dialog_holder').load(OC.filePath('contacts', 'ajax', 'editaddress.php')+q, function(jsondata){ + if(jsondata.status != 'error'){ + $('#edit_address_dialog' ).dialog({ /*modal: true,*/ height: 'auto', width: 'auto', buttons: { @@ -803,7 +985,10 @@ Contacts={ open : function(event, ui) { // load 'ADR' property - maybe :-P }*/ - }); + }); + } else { + alert(jsondata.data.message); + } }); } }, @@ -867,8 +1052,8 @@ Contacts={ form.submit(); } }, - loadPhoto:function(){ - if(this.data.PHOTO) { + loadPhoto:function(force){ + if(this.data.PHOTO||force==true) { $.getJSON('ajax/loadphoto.php',{'id':this.id},function(jsondata){ if(jsondata.status == 'success'){ //alert(jsondata.data.page); @@ -1006,13 +1191,17 @@ Contacts={ if($('#chooseaddressbook_dialog').dialog('isOpen') == true){ $('#chooseaddressbook_dialog').dialog('moveToTop'); }else{ - $('#dialog_holder').load(OC.filePath('contacts', 'ajax', 'chooseaddressbook.php'), function(){ - $('#chooseaddressbook_dialog').dialog({ - width : 600, - close : function(event, ui) { - $(this).dialog('destroy').remove(); - } - }); + $('#dialog_holder').load(OC.filePath('contacts', 'ajax', 'chooseaddressbook.php'), function(jsondata){ + if(jsondata.status != 'error'){ + $('#chooseaddressbook_dialog').dialog({ + width : 600, + close : function(event, ui) { + $(this).dialog('destroy').remove(); + } + }); + } else { + alert(jsondata.data.message); + } }); } }, @@ -1121,6 +1310,7 @@ Contacts={ $(document).ready(function(){ Contacts.UI.loadHandlers(); + Categories.changed = Contacts.UI.Card.categoriesChanged; /** * Show the Addressbook chooser @@ -1189,7 +1379,8 @@ $(document).ready(function(){ // NOTE: For some reason the selector doesn't work when I select by '.contacts_property' too... // I do the filtering in the event handler instead. - $('input[type="text"],input[type="checkbox"],input[type="email"],input[type="tel"],input[type="date"], select').live('change', function(){ + //$('input[type="text"],input[type="checkbox"],input[type="email"],input[type="tel"],input[type="date"], select').live('change', function(){ + $('.contacts_property').live('change', function(){ Contacts.UI.Card.saveProperty(this); }); @@ -1298,11 +1489,29 @@ $(document).ready(function(){ xhr.send(file); } + $('body').live('click',function(e){ + if(!$(e.target).is('#contacts_propertymenu_button')) { + $('#contacts_propertymenu').hide(); + } + }); $('#contacts_propertymenu_button').live('click',function(){ - $('#contacts_propertymenu').is(':hidden') && $('#contacts_propertymenu').slideDown() || $('#contacts_propertymenu').slideUp(); + var menu = $('#contacts_propertymenu'); + if(menu.is(':hidden')) { + menu.show(); + menu.find('ul').focus(); + } else { + menu.hide(); + } }); $('#contacts_propertymenu a').live('click',function(){ Contacts.UI.Card.addProperty(this); $('#contacts_propertymenu').hide(); }); }); + +String.prototype.strip_tags = function(){ + tags = this; + stripped = tags.replace(/[\<\>]/gi, ""); + return stripped; +} + diff --git a/apps/contacts/lib/vcard.php b/apps/contacts/lib/vcard.php index 99b1edd656..3c95dd19ab 100644 --- a/apps/contacts/lib/vcard.php +++ b/apps/contacts/lib/vcard.php @@ -4,6 +4,7 @@ * * @author Jakob Sack * @copyright 2011 Jakob Sack mail@jakobsack.de + * @copyright 2012 Thomas Tanghus * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE @@ -275,6 +276,29 @@ class OC_Contacts_VCard{ return $newid; } + /** + * @brief Mass updates an array of cards + * @param array $objects An array of [id, carddata]. + */ + public static function updateDataByID($objects){ + $stmt = OC_DB::prepare( 'UPDATE *PREFIX*contacts_cards SET carddata = ?, lastmodified = ? WHERE id = ?' ); + $now = new DateTime; + foreach($objects as $object) { + $vcard = OC_VObject::parse($object[1]); + if(!is_null($vcard)){ + $vcard->setString('REV', $now->format(DateTime::W3C)); + $data = $vcard->serialize(); + try { + $result = $stmt->execute(array($data,time(),$object[0])); + //OC_Log::write('contacts','OC_Contacts_VCard::updateDataByID, id: '.$object[0].': '.$object[1],OC_Log::DEBUG); + } catch(Exception $e) { + OC_Log::write('contacts','OC_Contacts_VCard::updateDataByID:, exception: '.$e->getMessage(),OC_Log::DEBUG); + OC_Log::write('contacts','OC_Contacts_VCard::updateDataByID, id: '.$object[0],OC_Log::DEBUG); + } + } + } + } + /** * @brief edits a card * @param integer $id id of card @@ -378,6 +402,43 @@ class OC_Contacts_VCard{ return true; } + /** + * @brief Escapes delimiters from an array and returns a string. + * @param array $value + * @param char $delimiter + * @return string + */ + public static function escapeDelimiters($value, $delimiter=';') { + foreach($value as &$i ) { + $i = implode("\\$delimiter", explode($delimiter, $i)); + } + return implode($delimiter, $value); + } + + + /** + * @brief Creates an array out of a multivalue property + * @param string $value + * @param char $delimiter + * @return array + */ + public static function unescapeDelimiters($value, $delimiter=';') { + $array = explode($delimiter,$value); + for($i=0;$ivalue; //$value = htmlspecialchars($value); if($property->name == 'ADR' || $property->name == 'N'){ - $value = OC_VObject::unescapeSemicolons($value); + $value = self::unescapeDelimiters($value); + } elseif($property->name == 'CATEGORIES') { + $value = self::unescapeDelimiters($value, ','); } $temp = array( 'name' => $property->name, diff --git a/apps/contacts/templates/part.contact.php b/apps/contacts/templates/part.contact.php index 5be20964f4..59bb6c2cc2 100644 --- a/apps/contacts/templates/part.contact.php +++ b/apps/contacts/templates/part.contact.php @@ -13,6 +13,7 @@ $id = isset($_['id']) ? $_['id'] : '';
    • t('Phone'); ?>
    • t('Email'); ?>
    • t('Address'); ?>
    • +
    • t('Note'); ?>
    • @@ -45,7 +46,7 @@ $id = isset($_['id']) ? $_['id'] : '';
      +
      @@ -53,8 +54,19 @@ $id = isset($_['id']) ? $_['id'] : ''; +
      +
      + + +
      + diff --git a/lib/vcategories.php b/lib/vcategories.php index 250aa608c1..7a31a5268d 100644 --- a/lib/vcategories.php +++ b/lib/vcategories.php @@ -49,12 +49,14 @@ class OC_VCategories { * @param $user The user whos data the object will operate on. This * parameter should normally be omitted but to make an app able to * update categories for all users it is made possible to provide it. + * @param $defcategories An array of default categories to be used if none is stored. + * NOTE: Not implemented. */ - public function __construct($app, $user=null) { + public function __construct($app, $user=null, $defcategories=null) { $this->app = $app; $this->user = is_null($user) ? OC_User::getUser() : $user; $categories = trim(OC_Preferences::getValue($this->user, $app, self::PREF_CATEGORIES_LABEL, '')); - $this->categories = $categories != '' ? OC_VObject::unescapeSemicolons($categories) : array(); + $this->categories = $categories != '' ? unserialize($categories) : array(); } /** @@ -62,6 +64,7 @@ class OC_VCategories { * @returns array containing the categories as strings. */ public function categories() { + OC_Log::write('core','OC_VCategories::categories: '.print_r($this->categories, true), OC_Log::DEBUG); return $this->categories; } @@ -81,7 +84,7 @@ class OC_VCategories { * @param $sync bool When true, save the categories * @returns bool Returns false on error. */ - public function add($names, $sync=true) { + public function add($names, $sync=false) { if(!is_array($names)) { $names = array($names); } @@ -95,7 +98,7 @@ class OC_VCategories { if(count($newones) > 0) { $this->categories = array_merge($this->categories, $newones); natcasesort($this->categories); // Dunno if this is necessary - if($sync) { + if($sync === true) { $this->save(); } } @@ -106,7 +109,7 @@ class OC_VCategories { * @brief Extracts categories from a vobject and add the ones not already present. * @param $vobject The instance of OC_VObject to load the categories from. */ - public function loadFromVObject($vobject, $sync=true) { + public function loadFromVObject($vobject, $sync=false) { $this->add($vobject->getAsArray('CATEGORIES'), $sync); } @@ -126,14 +129,15 @@ class OC_VCategories { * } * $categories->rescan($objects); */ - public function rescan($objects) { + public function rescan($objects, $sync=true) { $this->categories = array(); foreach($objects as $object) { + //OC_Log::write('core','OC_VCategories::rescan: '.substr($object, 0, 100).'(...)', OC_Log::DEBUG); $vobject = OC_VObject::parse($object); if(!is_null($vobject)) { - $this->loadFromVObject($vobject, false); + $this->loadFromVObject($vobject, $sync); } else { - OC_Log::write('core','OC_VCategories::rescan, unable to parse. ID: '.$value[0].', '.substr($value[1], 0, 20).'(...)', OC_Log::DEBUG); + OC_Log::write('core','OC_VCategories::rescan, unable to parse. ID: '.$value[0].', '.substr($value[1], 0, 50).'(...)', OC_Log::DEBUG); } } $this->save(); @@ -142,35 +146,51 @@ class OC_VCategories { /** * @brief Save the list with categories */ - public function save() { - $escaped_categories = OC_VObject::escapeSemicolons($this->categories); + private function save() { + $escaped_categories = serialize($this->categories); + OC_Log::write('core','OC_VCategories::save: '.print_r($this->categories, true), OC_Log::DEBUG); OC_Preferences::setValue($this->user, $this->app, self::PREF_CATEGORIES_LABEL, $escaped_categories); } /** - * @brief Delete a category from the db and from all the vobject supplied - * @param $name + * @brief Delete categories from the db and from all the vobject supplied + * @param $names An array of categories to delete * @param $objects An array of arrays with [id,vobject] (as text) pairs suitable for updating the apps object table. */ - public function delete($name, array &$objects) { - if(!$this->hasCategory($name)) { - return; + public function delete($names, array &$objects) { + if(!is_array($names)) { + $names = array($names); + } + OC_Log::write('core','OC_VCategories::delete, before: '.print_r($this->categories, true), OC_Log::DEBUG); + foreach($names as $name) { + OC_Log::write('core','OC_VCategories::delete: '.$name, OC_Log::DEBUG); + if($this->hasCategory($name)) { + OC_Log::write('core','OC_VCategories::delete: '.$name.' got it', OC_Log::DEBUG); + unset($this->categories[$this->array_searchi($name, $this->categories)]); + } } - unset($this->categories[$this->array_searchi($name, $this->categories)]); $this->save(); + OC_Log::write('core','OC_VCategories::delete, after: '.print_r($this->categories, true), OC_Log::DEBUG); foreach($objects as $key=>&$value) { $vobject = OC_VObject::parse($value[1]); if(!is_null($vobject)){ $categories = $vobject->getAsArray('CATEGORIES'); - $idx = $this->array_searchi($name, $categories); - if($idx) { - unset($categories[$this->array_searchi($name, $categories)]); - $vobject->setString('CATEGORIES', implode(',', $categories)); - $value[1] = $vobject->serialize(); - $objects[$key] = $value; + //OC_Log::write('core','OC_VCategories::delete, before: '.$key.': '.print_r($categories, true), OC_Log::DEBUG); + foreach($names as $name) { + $idx = $this->array_searchi($name, $categories); + OC_Log::write('core','OC_VCategories::delete, loop: '.$name.', '.print_r($idx, true), OC_Log::DEBUG); + if($idx !== false) { + OC_Log::write('core','OC_VCategories::delete, unsetting: '.$categories[$this->array_searchi($name, $categories)], OC_Log::DEBUG); + unset($categories[$this->array_searchi($name, $categories)]); + //unset($categories[$idx]); + } } + OC_Log::write('core','OC_VCategories::delete, after: '.$key.': '.print_r($categories, true), OC_Log::DEBUG); + $vobject->setString('CATEGORIES', implode(',', $categories)); + $value[1] = $vobject->serialize(); + $objects[$key] = $value; } else { - OC_Log::write('core','OC_VCategories::delete, unable to parse. ID: '.$value[0].', '.substr($value[1], 0, 20).'(...)', OC_Log::DEBUG); + OC_Log::write('core','OC_VCategories::delete, unable to parse. ID: '.$value[0].', '.substr($value[1], 0, 50).'(...)', OC_Log::DEBUG); } } } From d8d293966852e28168c3ec42c79c2a271a8c8ade Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Wed, 7 Mar 2012 17:31:01 +0100 Subject: [PATCH 033/132] dont use numRows and fix some of the gallary hooks --- apps/gallery/ajax/galleryOp.php | 4 ++-- apps/gallery/lib/album.php | 7 +++++++ apps/gallery/lib/hooks_handlers.php | 31 +++++++++++++++-------------- apps/gallery/lib/scanner.php | 8 ++++---- 4 files changed, 29 insertions(+), 21 deletions(-) diff --git a/apps/gallery/ajax/galleryOp.php b/apps/gallery/ajax/galleryOp.php index 74ac905d07..f33eb46041 100644 --- a/apps/gallery/ajax/galleryOp.php +++ b/apps/gallery/ajax/galleryOp.php @@ -102,9 +102,9 @@ function handleGetGallery($path) { while ($r = $result->fetchRow()) { $album_name = $r['album_name']; - $tmp_res = OC_Gallery_Photo::find($r['album_id']); + $size=OC_Gallery_Album::getAlbumSize($r['album_id']); - $a[] = array('name' => utf8_encode($album_name), 'numOfItems' => min($tmp_res->numRows(), 10)); + $a[] = array('name' => utf8_encode($album_name), 'numOfItems' => min($size, 10)); } $result = OC_Gallery_Photo::find($album_details['album_id']); diff --git a/apps/gallery/lib/album.php b/apps/gallery/lib/album.php index 317e8209de..5adb57b554 100644 --- a/apps/gallery/lib/album.php +++ b/apps/gallery/lib/album.php @@ -107,6 +107,13 @@ class OC_Gallery_Album { rename($thumbpath.$oldname.'.png', $thumbpath.$newname.'.png'); } + public static function getAlbumSize($id){ + $sql = 'SELECT COUNT(*) as size FROM *PREFIX*gallery_photos WHERE album_id = ?'; + $stmt = OC_DB::prepare($sql); + $result=$stmt->execute(array($id))->fetchRow(); + return $result['size']; + } + } ?> diff --git a/apps/gallery/lib/hooks_handlers.php b/apps/gallery/lib/hooks_handlers.php index 046866e5c5..3c101b1f8a 100644 --- a/apps/gallery/lib/hooks_handlers.php +++ b/apps/gallery/lib/hooks_handlers.php @@ -37,7 +37,7 @@ class OC_Gallery_Hooks_Handlers { } private static function directoryContainsPhotos($dirpath) { - $dirhandle = opendir(OC::$CONFIG_DATADIRECTORY.$dirpath); + $dirhandle = OC_Filesystem::opendir($dirpath.'/'); if ($dirhandle != FALSE) { while (($filename = readdir($dirhandle)) != FALSE) { if ($filename[0] == '.') continue; @@ -76,9 +76,9 @@ class OC_Gallery_Hooks_Handlers { public static function removePhoto($params) { $path = $params[OC_Filesystem::signal_param_path]; - if (OC_Filesystem::is_dir($path) && self::directoryContainsPhotos($path)) { + if (OC_Filesystem::is_dir($path.'/') && self::directoryContainsPhotos($path)) { if(!self::pathInRoot($path)) return; - OC_Gallery_Album::removeByPath($path.'/', OC_User::getUser()); + OC_Gallery_Album::removeByPath($path, OC_User::getUser()); } elseif (self::isPhoto($path)) { OC_Gallery_Photo::removeByPath($path); } @@ -87,11 +87,11 @@ class OC_Gallery_Hooks_Handlers { public static function renamePhoto($params) { $oldpath = $params[OC_Filesystem::signal_param_oldpath]; $newpath = $params[OC_Filesystem::signal_param_newpath]; - if (OC_Filesystem::is_dir($newpath) && self::directoryContainsPhotos($newpath)) { + if (OC_Filesystem::is_dir($newpath.'/') && self::directoryContainsPhotos($newpath)) { OC_Gallery_Album::changePath($oldpath, $newpath, OC_User::getUser()); - } elseif (!self::isPhoto($newpath)) { - $olddir = substr($oldpath, 0, strrpos($oldpath, '/')); - $newdir = substr($newpath, 0, strrpos($newpath, '/')); + } elseif (self::isPhoto($newpath)) { + $olddir = dirname($oldpath); + $newdir = dirname($newpath); if ($olddir == '') $olddir = '/'; if ($newdir == '') $newdir = '/'; if (!self::isPhoto($newpath)) return; @@ -101,25 +101,26 @@ class OC_Gallery_Hooks_Handlers { $oldAlbumId; if ($olddir == $newdir) { // album changing is not needed - $album = OC_Gallery_Album::find(OC_User::getUser(), null, $olddir); - if ($album->numRows() == 0) { - $album = self::createAlbum($newdir); + $albums = OC_Gallery_Album::find(OC_User::getUser(), null, $olddir); + $album = $albums->fetchRow(); + if (!$album) { + $albums = self::createAlbum($newdir); + $album = $albums->fetchRow(); } - $album = $album->fetchRow(); $newAlbumId = $oldAlbumId = $album['album_id']; } else { $newalbum = OC_Gallery_Album::find(OC_User::getUser(), null, $newdir); $oldalbum = OC_Gallery_Album::find(OC_User::getUser(), null, $olddir); - if ($newalbum->numRows() == 0) { + if (!($newalbum = $newalbum->fetchRow())) { $newalbum = self::createAlbum($newdir); + $newalbum = $newalbum->fetchRow(); } - $newalbum = $newalbum->fetchRow(); - if ($oldalbum->numRows() == 0) { + $oldalbum = $oldalbum->fetchRow(); + if (!$oldalbum) { OC_Gallery_Photo::create($newalbum['album_id'], $newpath); return; } - $oldalbum = $oldalbum->fetchRow(); $newAlbumId = $newalbum['album_id']; $oldAlbumId = $oldalbum['album_id']; diff --git a/apps/gallery/lib/scanner.php b/apps/gallery/lib/scanner.php index 1e8fdb63fb..dbe1abff10 100644 --- a/apps/gallery/lib/scanner.php +++ b/apps/gallery/lib/scanner.php @@ -62,15 +62,15 @@ class OC_Gallery_Scanner { $result = OC_Gallery_Album::find(OC_User::getUser(), /*$current_album['name']*/ null, $path); // don't duplicate galleries with same path (bug oc-33) - if ($result->numRows() == 0 && count($current_album['images'])) { - OC_Gallery_Album::create(OC_User::getUser(), $current_album['name'], $path); + if (!($albumId = $result->fetchRow()) && count($current_album['images'])) { + OC_Gallery_Album::create(OC_User::getUser(), $current_album['name'], $path); $result = OC_Gallery_Album::find(OC_User::getUser(), $current_album['name']); + $albumId = $result->fetchRow(); } - $albumId = $result->fetchRow(); $albumId = $albumId['album_id']; foreach ($current_album['images'] as $img) { $result = OC_Gallery_Photo::find($albumId, $img); - if ($result->numRows() == 0) { + if (!$result->fetchRow()) { OC_Gallery_Photo::create($albumId, $img); } } From cf5d63f0abc2b4537098962ad5051180861f965b Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Wed, 7 Mar 2012 18:58:10 +0100 Subject: [PATCH 034/132] some js cleanup for gallary also tabs no spaces --- apps/gallery/ajax/galleryOp.php | 2 +- apps/gallery/js/album_cover.js | 309 ++++++++++++++++---------------- apps/gallery/js/albums.js | 192 ++++++++++---------- 3 files changed, 252 insertions(+), 251 deletions(-) diff --git a/apps/gallery/ajax/galleryOp.php b/apps/gallery/ajax/galleryOp.php index f33eb46041..64f1b1697b 100644 --- a/apps/gallery/ajax/galleryOp.php +++ b/apps/gallery/ajax/galleryOp.php @@ -104,7 +104,7 @@ function handleGetGallery($path) { $album_name = $r['album_name']; $size=OC_Gallery_Album::getAlbumSize($r['album_id']); - $a[] = array('name' => utf8_encode($album_name), 'numOfItems' => min($size, 10)); + $a[] = array('name' => utf8_encode($album_name), 'numOfItems' => min($size, 10),'path'=>$r['album_path']); } $result = OC_Gallery_Photo::find($album_details['album_id']); diff --git a/apps/gallery/js/album_cover.js b/apps/gallery/js/album_cover.js index 98f2907281..71de1adae1 100644 --- a/apps/gallery/js/album_cover.js +++ b/apps/gallery/js/album_cover.js @@ -1,184 +1,187 @@ var actual_cover; -var paths = ''; +var paths = []; var crumbCount = 0; $(document).ready(returnToElement(0)); function returnToElement(num) { - while (crumbCount != num) { - $('#g-album-navigation .last').remove(); - $('#g-album-navigation .crumb :last').parent().addClass('last'); - crumbCount--; - paths = paths.substring(0, paths.lastIndexOf('\/')); - } - $.getJSON('ajax/galleryOp.php', {operation: 'get_gallery', path: paths }, albumClickHandler); + while (crumbCount != num) { + $('#g-album-navigation .last').remove(); + $('#g-album-navigation .crumb :last').parent().addClass('last'); + crumbCount--; + paths.pop(); + } + path=paths[paths.length-1]; + $.getJSON(OC.filePath('gallery','ajax','galleryOp.php'), {operation: 'get_gallery', path: path }, albumClickHandler); } -function albumClick(e) { - var title = decodeURIComponent(escape(e.data.title)); - paths += '/' + title; - crumbCount++; - $.getJSON('ajax/galleryOp.php', {operation: 'get_gallery', path: paths }, albumClickHandler); - if ($('#g-album-navigation :last-child')) - $('#g-album-navigation :last-child').removeClass('last'); - $('#g-album-navigation').append(''); +function albumClick(title,path) { + paths.push(path); + crumbCount++; + $.getJSON(OC.filePath('gallery','ajax','galleryOp.php'), {operation: 'get_gallery', path: path }, albumClickHandler); + if ($('#g-album-navigation :last-child')) + $('#g-album-navigation :last-child').removeClass('last'); + $('#g-album-navigation').append(''); } function albumClickHandler(r) { - Albums.photos = []; - Albums.albums = []; - if (r.status == 'success') { - for (var i in r.albums) { - var a = r.albums[i]; - Albums.add(a.name, a.numOfItems); - } - for (var i in r.photos) { - Albums.photos.push(r.photos[i]); - } - var targetDiv = document.getElementById('gallery_list'); - if (targetDiv) { - $(targetDiv).html(''); - Albums.display(targetDiv); - //$('#gallery_list').sortable({revert:true}); - $('.album').each(function(i, el) { - $(el).click({title:$(el).attr('title')}, albumClick); - //$(el).draggable({connectToSortable: '#gallery_list', handle: '.dummy'}); - }); - } else { - OC.dialogs.alert(t('gallery', 'Error: no such layer `gallery_list`'), t('gallery', 'Internal error')); - } - } else { - OC.dialogs.alert(t('gallery', 'Error: ') + r.message, t('gallery', 'Internal error')); - } + Albums.photos = []; + Albums.albums = []; + if (r.status == 'success') { + for (var i in r.albums) { + var a = r.albums[i]; + Albums.add(a.name, a.numOfItems,a.path); + } + for (var i in r.photos) { + Albums.photos.push(r.photos[i]); + } + var targetDiv = document.getElementById('gallery_list'); + if (targetDiv) { + $(targetDiv).html(''); + Albums.display(targetDiv); + //$('#gallery_list').sortable({revert:true}); + $('.album').each(function(i, el) { + $(el).click(albumClick.bind(null,$(el).attr('title'),$(el).data('path'))); + //$(el).draggable({connectToSortable: '#gallery_list', handle: '.dummy'}); + }); + } else { + OC.dialogs.alert(t('gallery', 'Error: no such layer `gallery_list`'), t('gallery', 'Internal error')); + } + } else { + OC.dialogs.alert(t('gallery', 'Error: ') + r.message, t('gallery', 'Internal error')); + } } function createNewAlbum() { - var name = prompt("album name", ""); - if (name != null && name != "") { - $.getJSON("ajax/createAlbum.php", {album_name: name}, function(r) { - if (r.status == "success") { - var v = ''; - $('div#gallery_list').append(v); - } - }); - } + var name = prompt("album name", ""); + if (name != null && name != "") { + $.getJSON(OC.filePath('gallery','ajax','createAlbum.php'), {album_name: name}, function(r) { + if (r.status == "success") { + var v = ''; + $('div#gallery_list').append(v); + } + }); + } } var albumCounter = 0; var totalAlbums = 0; function scanForAlbums(cleanup) { - cleanup = cleanup?true:false; - var albumCounter = 0; - var totalAlbums = 0; - $('#g-scan-button').attr('disabled', 'true'); - $.getJSON('ajax/galleryOp.php?operation=filescan', {cleanup: cleanup}, function(r) { + cleanup = cleanup?true:false; + var albumCounter = 0; + var totalAlbums = 0; + $('#g-scan-button').attr('disabled', 'true'); + $.getJSON(OC.filePath('gallery','ajax','galleryOp.php'), {cleanup: cleanup,operation:'filescan'}, function(r) { - if (r.status == 'success') { - totalAlbums = r.paths.length; - if (totalAlbums == 0) { - $('#notification').text(t('gallery', "No photos found")).fadeIn().slideDown().delay(3000).fadeOut().slideUp(); - return; - } - $('#scanprogressbar').progressbar({ value: (albumCounter/totalAlbums)*100 }).fadeIn(); - for(var a in r.paths) { - $.getJSON('ajax/galleryOp.php',{operation:'partial_create','path':r.paths[a]}, function(r) { + if (r.status == 'success') { + totalAlbums = r.paths.length; + if (totalAlbums == 0) { + $('#notification').text(t('gallery', "No photos found")).fadeIn().slideDown().delay(3000).fadeOut().slideUp(); + return; + } + $('#scanprogressbar').progressbar({ value: (albumCounter/totalAlbums)*100 }).fadeIn(); + for(var a in r.paths) { + $.getJSON(OC.filePath('gallery','ajax','galleryOp.php'),{operation:'partial_create','path':r.paths[a]}, function(r) { - albumCounter++; - $('#scanprogressbar').progressbar({ value: (albumCounter/totalAlbums)*100 }); - if (albumCounter == totalAlbums) { - $('#scanprogressbar').fadeOut(); - var targetDiv = document.getElementById('gallery_list'); - if (targetDiv) { - targetDiv.innerHTML = ''; - Albums.photos = []; - Albums.albums = []; - returnToElement(0); - } else { - alert('Error occured: no such layer `gallery_list`'); - } - $('#g-scan-button').attr('disabled', null); - } - }); - } - } else { - alert('Error occured: ' + r.message); - } - }); + albumCounter++; + $('#scanprogressbar').progressbar({ value: (albumCounter/totalAlbums)*100 }); + if (albumCounter == totalAlbums) { + $('#scanprogressbar').fadeOut(); + var targetDiv = document.getElementById('gallery_list'); + if (targetDiv) { + targetDiv.innerHTML = ''; + Albums.photos = []; + Albums.albums = []; + returnToElement(0); + } else { + alert('Error occured: no such layer `gallery_list`'); + } + $('#g-scan-button').attr('disabled', null); + } + }); + } + } else { + alert('Error occured: ' + r.message); + } + }); } function galleryRemove(albumName) { - OC.dialogs.confirm(t('gallery', 'Do you want to remove album ') + decodeURIComponent(escape(albumName)), - t('gallery', 'Remove confirmation'), - function(decision) { - if (decision) { - $.getJSON("ajax/galleryOp.php", {operation: "remove", name: decodeURIComponent(escape(albumName))}, function(r) { - if (r.status == "success") { - $(".gallery_box").filterAttr('data-album',albumName).remove(); - Albums.remove(albumName); - } else { - OC.dialogs.alert(r.cause, "Error"); - } - }); - } - }); + OC.dialogs.confirm(t('gallery', 'Do you want to remove album ') + decodeURIComponent(escape(albumName)), + t('gallery', 'Remove confirmation'), + function(decision) { + if (decision) { + $.getJSON(OC.filePath('gallery','ajax','galleryOp.php'), {operation: "remove", name: decodeURIComponent(escape(albumName))}, function(r) { + if (r.status == "success") { + $(".gallery_box").filterAttr('data-album',albumName).remove(); + Albums.remove(albumName); + } else { + OC.dialogs.alert(r.cause, "Error"); + } + }); + } + } + ); } function galleryRename(name) { - OC.dialogs.prompt(t('gallery', 'New album name'), - t('gallery', 'Change name'), - name, - function(newname) { - if (newname == name || newname == '') return; - if (Albums.find(newname)) { - OC.dialogs.alert('Album ' + newname + ' exists', 'Alert'); - return; - } - $.getJSON('ajax/galleryOp.php', {operation: 'rename', oldname: name, newname: newname}, function(r) { - if (r.status == 'success') { - Albums.rename($(".gallery_box").filterAttr('data-album',name), newname); - } else { - OC.dialogs.alert('Error: ' + r.cause, 'Error'); - } - }); - }); + OC.dialogs.prompt(t('gallery', 'New album name'), + t('gallery', 'Change name'), + name, + function(newname) { + if (newname == name || newname == '') return; + if (Albums.find(newname)) { + OC.dialogs.alert('Album ' + newname + ' exists', 'Alert'); + return; + } + $.getJSON(OC.filePath('gallery','ajax','galleryOp.php'), {operation: 'rename', oldname: name, newname: newname}, function(r) { + if (r.status == 'success') { + Albums.rename($(".gallery_box").filterAttr('data-album',name), newname); + } else { + OC.dialogs.alert('Error: ' + r.cause, 'Error'); + } + }); + } + ); } function settings() { - $( '#g-dialog-settings' ).dialog({ - height: 180, - width: 350, - modal: false, - buttons: [{ - text: t('gallery', 'Apply'), - click: function() { - var scanning_root = $('#g-scanning-root').val(); - var disp_order = $('#g-display-order option:selected').val(); - if (scanning_root == '') { - alert('Scanning root cannot be empty'); - return; - } - $.getJSON('ajax/galleryOp.php', {operation: 'store_settings', root: scanning_root, order: disp_order}, function(r) { - if (r.status == 'success') { - if (r.rescan == 'yes') { - $('#g-dialog-settings').dialog('close'); - Albums.clear(document.getElementById('gallery_list')); - scanForAlbums(true); - return; - } - } else { - alert('Error: ' + r.cause); - return; - } - $('#g-dialog-settings').dialog('close'); - }); - } - }, - { - text: t('gallery', 'Cancel'), - click: function() { - $(this).dialog('close'); - } - } - ], - }); + $( '#g-dialog-settings' ).dialog({ + height: 180, + width: 350, + modal: false, + buttons: [ + { + text: t('gallery', 'Apply'), + click: function() { + var scanning_root = $('#g-scanning-root').val(); + var disp_order = $('#g-display-order option:selected').val(); + if (scanning_root == '') { + alert('Scanning root cannot be empty'); + return; + } + $.getJSON(OC.filePath('gallery','ajax','galleryOp.php'), {operation: 'store_settings', root: scanning_root, order: disp_order}, function(r) { + if (r.status == 'success') { + if (r.rescan == 'yes') { + $('#g-dialog-settings').dialog('close'); + Albums.clear(document.getElementById('gallery_list')); + scanForAlbums(true); + return; + } + } else { + alert('Error: ' + r.cause); + return; + } + $('#g-dialog-settings').dialog('close'); + }); + } + }, + { + text: t('gallery', 'Cancel'), + click: function() { + $(this).dialog('close'); + } + } + ], + }); } diff --git a/apps/gallery/js/albums.js b/apps/gallery/js/albums.js index 3882deb514..afdfbd3cc8 100644 --- a/apps/gallery/js/albums.js +++ b/apps/gallery/js/albums.js @@ -1,100 +1,98 @@ Albums={ - // album item in this array should look as follow - // {name: string, - // numOfCovers: int} - // - // previews array should be an array of base64 decoded images - // to display to user as preview picture when scrolling throught - // the album cover - albums:new Array(), - photos:new Array(), - // add simply adds new album to internal structure - // however albums names must be unique so other - // album with the same name wont be insered, - // and false will be returned - // true on success - add: function(album_name, num) { - if (Albums.albums[album_name] != undefined) return false; - Albums.albums[album_name] = {name: album_name, numOfCovers: num}; - return true; - }, - // remove element with given name - // returns remove element or undefined if no such element was present - remove: function(name) { - var i = -1, tmp = 0; - for (var a in Albums.albums) { - if (a.name == name) { - i = tmp; - break; - } - tmp++; - } - if (i != -1) { - return Albums.albums.splice(i,1); - } - return undefined; - }, - // return element which match given name - // of undefined if such element do not exist - find: function(name) { - return Albums.albums[name]; - }, - // displays gallery in linear representation - // on given element, and apply default styles for gallery - display: function(element) { - var displayTemplate = ''; - for (var i in Albums.albums) { - var a = Albums.albums[i]; - var local=$(displayTemplate); - local.attr('title', a.name); - local.attr('data-album',a.name); - $(".gallery_album_decoration a.rename", local).bind('click', {name: a.name},function(event){ - event.preventDefault(); - event.stopPropagation(); - galleryRename(event.data.name); - }); - $(".gallery_album_decoration a.remove", local).bind('click', {name: a.name},function(event){ - event.preventDefault(); - event.stopPropagation(); - galleryRemove(event.data.name); - }); - // $("a.view", local).attr('href','?view='+decodeURIComponent(escape(a.name))); - $('h1',local).text(decodeURIComponent(escape(a.name))); - $(".gallery_album_cover", local).attr('title',decodeURIComponent(escape(a.name))); - $(".gallery_album_cover", local).css('background-repeat', 'no-repeat'); - $(".gallery_album_cover", local).css('background-position', '0'); - $(".gallery_album_cover", local).css('background-image','url("ajax/galleryOp.php?operation=get_covers&albumname='+escape(a.name)+'")'); - $(".gallery_album_cover", local).mousemove(function(e) { - - var albumMetadata = Albums.find(this.title); - if (albumMetadata == undefined) { - return; - } - var x = Math.floor((e.layerX - this.offsetLeft)/(this.offsetWidth/albumMetadata.numOfCovers)); - x *= this.offsetWidth; - if (x < 0) x=0; - $(this).css('background-position', -x+'px 0'); - }); - $(element).append(local); - } - var photoDisplayTemplate = ''; - for (var i in Albums.photos) { - $(element).append(photoDisplayTemplate.replace("IMGPATH", escape(Albums.photos[i])).replace("URLPATH", escape(Albums.photos[i]))); - } - $("a[rel=images]").fancybox({ - 'titlePosition': 'inside' - }); - }, - rename: function(element, new_name) { - if (new_name) { - $(element).attr("data-album", new_name); - $("a.view", element).attr("href", "?view="+new_name); - $("h1", element).text(new_name); + // album item in this array should look as follow + // {name: string, + // numOfCovers: int} + // + // previews array should be an array of base64 decoded images + // to display to user as preview picture when scrolling throught + // the album cover + albums:new Array(), + photos:new Array(), + // add simply adds new album to internal structure + // however albums names must be unique so other + // album with the same name wont be insered, + // and false will be returned + // true on success + add: function(album_name, num,path) { + if (Albums.albums[album_name] != undefined) return false; + Albums.albums[album_name] = {name: album_name, numOfCovers: num, path:path}; + return true; + }, + // remove element with given name + // returns remove element or undefined if no such element was present + remove: function(name) { + var i = -1, tmp = 0; + for (var a in Albums.albums) { + if (a.name == name) { + i = tmp; + break; + } + tmp++; + } + if (i != -1) { + return Albums.albums.splice(i,1); + } + return undefined; + }, + // return element which match given name + // of undefined if such element do not exist + find: function(name) { + return Albums.albums[name]; + }, + // displays gallery in linear representation + // on given element, and apply default styles for gallery + display: function(element) { + var displayTemplate = ''; + for (var i in Albums.albums) { + var a = Albums.albums[i]; + var local=$(displayTemplate); + local.attr('title', a.name); + local.attr('data-path', a.path); + local.attr('data-album',a.name); + $(".gallery_album_decoration a.rename", local).bind('click', {name: a.name},function(name,event){ + event.preventDefault(); + event.stopPropagation(); + galleryRename(name); + }.bind(null,a.name)); + $(".gallery_album_decoration a.remove", local).bind('click', {name: a.name},function(name,event){ + event.preventDefault(); + event.stopPropagation(); + galleryRemove(name); + }.bind(null,a.name)); + $('h1',local).text(decodeURIComponent(escape(a.name))); + $(".gallery_album_cover", local).attr('title',decodeURIComponent(escape(a.name))); + $(".gallery_album_cover", local).css('background-repeat', 'no-repeat'); + $(".gallery_album_cover", local).css('background-position', '0'); + $(".gallery_album_cover", local).css('background-image','url("'+OC.filePath('gallery','ajax','galleryOp.php')+'?operation=get_covers&albumname='+escape(a.name)+'")'); + $(".gallery_album_cover", local).mousemove(function(e) { + var albumMetadata = Albums.find(this.title); + if (albumMetadata == undefined) { + return; + } + var x = Math.floor((e.layerX - this.offsetLeft)/(this.offsetWidth/albumMetadata.numOfCovers)); + x *= this.offsetWidth; + if (x < 0) x=0; + $(this).css('background-position', -x+'px 0'); + }); + $(element).append(local); + } + var photoDisplayTemplate = ''; + for (var i in Albums.photos) { + $(element).append(photoDisplayTemplate.replace("IMGPATH", escape(Albums.photos[i])).replace("URLPATH", escape(Albums.photos[i]))); + } + $("a[rel=images]").fancybox({ + 'titlePosition': 'inside' + }); + }, + rename: function(element, new_name) { + if (new_name) { + $(element).attr("data-album", new_name); + $("a.view", element).attr("href", "?view="+new_name); + $("h1", element).text(new_name); + } + }, + clear: function(element) { + Albums.albums = new Array(); + element.innerHTML = ''; } - }, - clear: function(element) { - Albums.albums = new Array(); - element.innerHTML = ''; - } - } From 018f0c4b72d9d2ca1c27c4c543a805b227745beb Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Wed, 7 Mar 2012 21:43:44 +0100 Subject: [PATCH 035/132] add option to add file from url --- files/ajax/newfile.php | 26 +++++++++++++-- files/ajax/newfolder.php | 4 +-- files/js/files.js | 69 ++++++++++++++++++++++++--------------- files/templates/index.php | 1 + 4 files changed, 69 insertions(+), 31 deletions(-) diff --git a/files/ajax/newfile.php b/files/ajax/newfile.php index afc444bc0a..2d1372f06e 100644 --- a/files/ajax/newfile.php +++ b/files/ajax/newfile.php @@ -6,15 +6,35 @@ require_once('../../lib/base.php'); OC_JSON::checkLoggedIn(); // Get the params -$dir = isset( $_GET['dir'] ) ? stripslashes($_GET['dir']) : ''; -$filename = isset( $_GET['filename'] ) ? stripslashes($_GET['filename']) : ''; -$content = isset( $_GET['content'] ) ? $_GET['content'] : ''; +$dir = isset( $_POST['dir'] ) ? stripslashes($_POST['dir']) : ''; +$filename = isset( $_POST['filename'] ) ? stripslashes($_POST['filename']) : ''; +$content = isset( $_POST['content'] ) ? $_POST['content'] : ''; +$source = isset( $_POST['source'] ) ? stripslashes($_POST['source']) : ''; if($filename == '') { OC_JSON::error(array("data" => array( "message" => "Empty Filename" ))); exit(); } +if($source){ + if(substr($source,0,8)!='https://' and substr($source,0,7)!='http://'){ + OC_JSON::error(array("data" => array( "message" => "Not a valid source" ))); + exit(); + } + $sourceStream=fopen($source,'rb'); + $target=$dir.'/'.$filename; + $result=OC_Filesystem::file_put_contents($target,$sourceStream); + if($result){ + $mime=OC_Filesystem::getMimetype($target); + OC_JSON::success(array("data" => array('mime'=>$mime))); + exit(); + }else{ + OC_JSON::error(array("data" => array( "message" => "Error while downloading ".$source. ' to '.$target ))); + exit(); + } +} + + if(OC_Files::newFile($dir, $filename, 'file')) { if($content){ OC_Filesystem::file_put_contents($dir.'/'.$filename,$content); diff --git a/files/ajax/newfolder.php b/files/ajax/newfolder.php index 6db045c4e1..228e369fbe 100644 --- a/files/ajax/newfolder.php +++ b/files/ajax/newfolder.php @@ -6,8 +6,8 @@ require_once('../../lib/base.php'); OC_JSON::checkLoggedIn(); // Get the params -$dir = isset( $_GET['dir'] ) ? stripslashes($_GET['dir']) : ''; -$foldername = isset( $_GET['foldername'] ) ? stripslashes($_GET['foldername']) : ''; +$dir = isset( $_POST['dir'] ) ? stripslashes($_POST['dir']) : ''; +$foldername = isset( $_POST['foldername'] ) ? stripslashes($_POST['foldername']) : ''; if(trim($foldername) == '') { OC_JSON::error(array("data" => array( "message" => "Empty Foldername" ))); diff --git a/files/js/files.js b/files/js/files.js index f5dc40ad45..a678e12cc2 100644 --- a/files/js/files.js +++ b/files/js/files.js @@ -127,20 +127,6 @@ $(document).ready(function() { procesSelection(); }); - $('#file_newfolder_form').submit(function(event) { - event.preventDefault(); - $.ajax({ - url: 'ajax/newfolder.php', - data: "dir="+$('#dir').val()+"&foldername="+$('#file_newfolder_name').val(), - complete: function(data){boolOperationFinished(data, function(){ - var date=new Date(); - FileList.addDir($('#file_newfolder_name').val(),0,date); - $('#file_newfolder_name').val('New Folder'); - $('#file_newfolder_name').blur(); - });} - }); - }); - $('#file_newfolder_name').click(function(){ if($('#file_newfolder_name').val() == 'New Folder'){ $('#file_newfolder_name').val(''); @@ -312,10 +298,10 @@ $(document).ready(function() { var name=$(this).val(); switch(type){ case 'file': - $.ajax({ - url: OC.filePath('files','ajax','newfile.php'), - data: "dir="+encodeURIComponent($('#dir').val())+"&filename="+encodeURIComponent(name)+'&content=%20%0A', - complete: function(data){boolOperationFinished(data, function(){ + $.post( + OC.filePath('files','ajax','newfile.php'), + {dir:$('#dir').val(),filename:name,content:" \n"}, + function(data){ var date=new Date(); FileList.addFile(name,0,date); var tr=$('tr').filterAttr('data-file',name); @@ -323,18 +309,49 @@ $(document).ready(function() { getMimeIcon('text/plain',function(path){ tr.find('td.filename').attr('style','background-image:url('+path+')'); }); - });} - }); + } + ); break; case 'folder': - $.ajax({ - url: OC.filePath('files','ajax','newfolder.php'), - data: "dir="+encodeURIComponent($('#dir').val())+"&foldername="+encodeURIComponent(name), - complete: function(data){boolOperationFinished(data, function(){ + $.post( + OC.filePath('files','ajax','newfolder.php'), + {dir:$('#dir').val(),foldername:name}, + function(data){ var date=new Date(); FileList.addDir(name,0,date); - });} - }); + } + ); + 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.',''); + } + $.post( + OC.filePath('files','ajax','newfile.php'), + {dir:$('#dir').val(),source:name,filename:localName}, + function(result){ + if(result.status == 'success'){ + var date=new Date(); + FileList.addFile(localName,0,date); + var tr=$('tr').filterAttr('data-file',localName); + tr.data('mime',result.data.mime); + getMimeIcon(result.data.mime,function(path){ + tr.find('td.filename').attr('style','background-image:url('+path+')'); + }); + }else{ + + } + } + ); break; } var li=$(this).parent(); diff --git a/files/templates/index.php b/files/templates/index.php index 7e9505dec2..7fc51c288e 100644 --- a/files/templates/index.php +++ b/files/templates/index.php @@ -7,6 +7,7 @@
      From 9ccf46d350f2a17ae8234a348ec668e1f06fd9ec Mon Sep 17 00:00:00 2001 From: Bart Visscher Date: Mon, 5 Mar 2012 22:02:44 +0100 Subject: [PATCH 036/132] Contacts: convert class attribute selectors to class selectors --- apps/contacts/js/contacts.js | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/apps/contacts/js/contacts.js b/apps/contacts/js/contacts.js index d033e3f21c..60ee8b9e56 100644 --- a/apps/contacts/js/contacts.js +++ b/apps/contacts/js/contacts.js @@ -68,7 +68,7 @@ Contacts={ return $(obj).parents('.propertycontainer').first().data('element'); }, showHideContactInfo:function() { - var show = ($('#emaillist li[class*="propertycontainer"]').length > 0 || $('#phonelist li[class*="propertycontainer"]').length > 0 || $('#addressdisplay dl[class*="propertycontainer"]').length > 0); + var show = ($('#emaillist li.propertycontainer').length > 0 || $('#phonelist li.propertycontainer').length > 0 || $('#addressdisplay dl.propertycontainer').length > 0); console.log('showHideContactInfo: ' + show); if(show) { $('#contact_communication').show(); @@ -82,19 +82,19 @@ Contacts={ switch (type) { case 'EMAIL': console.log('emails: '+$('#emaillist>li').length); - if($('#emaillist li[class*="propertycontainer"]').length == 0) { + if($('#emaillist li.propertycontainer').length == 0) { $('#emails').hide(); } break; case 'TEL': console.log('phones: '+$('#phonelist>li').length); - if($('#phonelist li[class*="propertycontainer"]').length == 0) { + if($('#phonelist li.propertycontainer').length == 0) { $('#phones').hide(); } break; case 'ADR': console.log('addresses: '+$('#addressdisplay>dl').length); - if($('#addressdisplay dl[class*="propertycontainer"]').length == 0) { + if($('#addressdisplay dl.propertycontainer').length == 0) { $('#addresses').hide(); } break; @@ -183,7 +183,7 @@ Contacts={ dateFormat : 'dd-mm-yy' }); // Style phone types - $('#phonelist').find('select[class*="contacts_property"]').multiselect({ + $('#phonelist').find('select.contacts_property').multiselect({ noneSelectedText: t('contacts', 'Select type'), header: false, selectedList: 4, @@ -373,7 +373,7 @@ Contacts={ loadSingleProperties:function() { var props = ['BDAY', 'NICKNAME', 'ORG']; // Clear all elements - $('#ident .propertycontainer[class*="propertycontainer"]').each(function(){ + $('#ident .propertycontainer').each(function(){ if(props.indexOf($(this).data('element')) > -1) { $(this).data('checksum', ''); $(this).find('input').val(''); @@ -518,8 +518,8 @@ Contacts={ var checksum = container.data('checksum'); var name = container.data('element'); console.log('saveProperty: ' + name); - var fields = container.find('input[class*="contacts_property"],select[class*="contacts_property"]').serializeArray(); - var q = container.find('input[class*="contacts_property"],select[class*="contacts_property"]').serialize(); + var fields = container.find('input.contacts_property,select.contacts_property').serializeArray(); + var q = container.find('input.contacts_property,select.contacts_property').serialize(); if(q == '' || q == undefined) { console.log('Couldn\'t serialize elements.'); Contacts.UI.loading(container, false); @@ -708,7 +708,7 @@ Contacts={ }, loadAddresses:function(){ $('#addresses').hide(); - $('#addressdisplay dl[class*="propertycontainer"]').remove(); + $('#addressdisplay dl.propertycontainer').remove(); for(var adr in this.data.ADR) { $('#addressdisplay dl').first().clone().insertAfter($('#addressdisplay dl').last()).show(); $('#addressdisplay dl').last().removeClass('template').addClass('propertycontainer'); @@ -920,15 +920,15 @@ Contacts={ }, addMail:function() { //alert('addMail'); - $('#emaillist li[class*="template"]:first-child').clone().appendTo($('#emaillist')).show(); - $('#emaillist li[class*="template"]:last-child').removeClass('template').addClass('propertycontainer'); + $('#emaillist li.template:first-child').clone().appendTo($('#emaillist')).show(); + $('#emaillist li.template:last-child').removeClass('template').addClass('propertycontainer'); $('#emaillist li:last-child').find('input[type="email"]').focus(); Contacts.UI.loadListHandlers(); return false; }, loadMails:function() { $('#emails').hide(); - $('#emaillist li[class*="propertycontainer"]').remove(); + $('#emaillist li.propertycontainer').remove(); for(var mail in this.data.EMAIL) { this.addMail(); //$('#emaillist li:first-child').clone().appendTo($('#emaillist')).show(); @@ -950,9 +950,9 @@ Contacts={ return false; }, addPhone:function() { - $('#phonelist li[class*="template"]:first-child').clone().appendTo($('#phonelist')); //.show(); - $('#phonelist li[class*="template"]:last-child').find('select').addClass('contacts_property'); - $('#phonelist li[class*="template"]:last-child').removeClass('template').addClass('propertycontainer'); + $('#phonelist li.template:first-child').clone().appendTo($('#phonelist')); //.show(); + $('#phonelist li.template:last-child').find('select').addClass('contacts_property'); + $('#phonelist li.template:last-child').removeClass('template').addClass('propertycontainer'); $('#phonelist li:last-child').find('input[type="text"]').focus(); Contacts.UI.loadListHandlers(); $('#phonelist li:last-child').find('select').multiselect({ @@ -966,7 +966,7 @@ Contacts={ }, loadPhones:function() { $('#phones').hide(); - $('#phonelist li[class*="propertycontainer"]').remove(); + $('#phonelist li.propertycontainer').remove(); for(var phone in this.data.TEL) { this.addPhone(); $('#phonelist li:last-child').find('select').multiselect('destroy'); From 46aa011ef90c02098ddfa75a93fe9bf2759b622a Mon Sep 17 00:00:00 2001 From: Bart Visscher Date: Mon, 5 Mar 2012 22:03:33 +0100 Subject: [PATCH 037/132] Contacts: Add Organisation as Name property choice --- apps/contacts/js/contacts.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/contacts/js/contacts.js b/apps/contacts/js/contacts.js index 60ee8b9e56..94876f5cd0 100644 --- a/apps/contacts/js/contacts.js +++ b/apps/contacts/js/contacts.js @@ -448,6 +448,9 @@ Contacts={ $('#fn_select option').remove(); $('#fn_select').combobox('value', this.fn); var names = [this.fullname, this.givname + ' ' + this.famname, this.famname + ' ' + this.givname, this.famname + ', ' + this.givname]; + if(this.data.ORG) { + names[names.length]=this.data.ORG[0].value; + } $.each(names, function(key, value) { $('#fn_select') .append($('') From 97ab706a6a1d85f9e37589c9f88cedbdfa817f6e Mon Sep 17 00:00:00 2001 From: Bart Visscher Date: Mon, 5 Mar 2012 22:05:30 +0100 Subject: [PATCH 038/132] Contacts: No random token for contactphoto --- apps/contacts/templates/part.contactphoto.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/contacts/templates/part.contactphoto.php b/apps/contacts/templates/part.contactphoto.php index 9e3f5876cd..8107650d16 100644 --- a/apps/contacts/templates/part.contactphoto.php +++ b/apps/contacts/templates/part.contactphoto.php @@ -3,7 +3,7 @@ $id = $_['id']; $wattr = isset($_['width'])?'width="'.$_['width'].'"':''; $hattr = isset($_['height'])?'height="'.$_['height'].'"':''; ?> - src="?id=&refresh=" /> + src="?id=" /> From ab760578f8141e5ab20345c2f84cb7a545c2e076 Mon Sep 17 00:00:00 2001 From: Bart Visscher Date: Mon, 5 Mar 2012 22:06:01 +0100 Subject: [PATCH 039/132] Allow overflow of rightcontent area --- core/css/styles.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/css/styles.css b/core/css/styles.css index 62f5299ef7..f5a181c452 100644 --- a/core/css/styles.css +++ b/core/css/styles.css @@ -60,7 +60,7 @@ input[type="submit"].highlight{ background:#ffc100; border:1px solid #db0; text- #leftcontent, .leftcontent { position:fixed; overflow: auto; top:6.4em; width:20em; background:#f8f8f8; border-right:1px solid #ddd; } #leftcontent li, .leftcontent li { background:#f8f8f8; padding:.3em .8em; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; -webkit-transition:background-color 500ms; -moz-transition:background-color 500ms; -o-transition:background-color 500ms; transition:background-color 500ms; } #leftcontent li:hover, #leftcontent li:active, #leftcontent li.active, .leftcontent li:hover, .leftcontent li:active, .leftcontent li.active { background:#eee; } -#rightcontent, .rightcontent { position:fixed; top: 6.4em; left: 32.5em; } +#rightcontent, .rightcontent { position:fixed; top: 6.4em; left: 32.5em; overflow: auto } /* LOG IN & INSTALLATION ------------------------------------------------------------ */ From 95995482034a607085d2cdc8000e5ea437c0cb1f Mon Sep 17 00:00:00 2001 From: Bart Visscher Date: Wed, 7 Mar 2012 21:27:03 +0100 Subject: [PATCH 040/132] Contacts: change card parameter type of VCard::edit and VCard::add changed to OC_VObject --- apps/contacts/ajax/addcard.php | 2 +- apps/contacts/ajax/addcontact.php | 2 +- apps/contacts/ajax/addproperty.php | 2 +- apps/contacts/ajax/deleteproperty.php | 2 +- apps/contacts/ajax/savecrop.php | 2 +- apps/contacts/ajax/saveproperty.php | 2 +- apps/contacts/ajax/setproperty.php | 2 +- apps/contacts/import.php | 14 ++-- apps/contacts/lib/app.php | 2 +- apps/contacts/lib/vcard.php | 109 ++++++++------------------ 10 files changed, 51 insertions(+), 88 deletions(-) diff --git a/apps/contacts/ajax/addcard.php b/apps/contacts/ajax/addcard.php index b1dc69a469..49a4a16170 100644 --- a/apps/contacts/ajax/addcard.php +++ b/apps/contacts/ajax/addcard.php @@ -92,7 +92,7 @@ foreach( $add as $propname){ } } } -$id = OC_Contacts_VCard::add($aid,$vcard->serialize()); +$id = OC_Contacts_VCard::add($aid,$vcard); if(!$id) { OC_JSON::error(array('data' => array('message' => OC_Contacts_App::$l10n->t('There was an error adding the contact.')))); OC_Log::write('contacts','ajax/addcard.php: Recieved non-positive ID on adding card: '.$id, OC_Log::ERROR); diff --git a/apps/contacts/ajax/addcontact.php b/apps/contacts/ajax/addcontact.php index 5d17631caa..839a391998 100644 --- a/apps/contacts/ajax/addcontact.php +++ b/apps/contacts/ajax/addcontact.php @@ -52,7 +52,7 @@ $vcard->setUID(); $vcard->setString('FN',$fn); $vcard->setString('N',$n); -$id = OC_Contacts_VCard::add($aid,$vcard->serialize()); +$id = OC_Contacts_VCard::add($aid,$vcard); if(!$id) { OC_JSON::error(array('data' => array('message' => OC_Contacts_App::$l10n->t('There was an error adding the contact.')))); OC_Log::write('contacts','ajax/addcontact.php: Recieved non-positive ID on adding card: '.$id, OC_Log::ERROR); diff --git a/apps/contacts/ajax/addproperty.php b/apps/contacts/ajax/addproperty.php index 028974e1c6..b6b5dc7c41 100644 --- a/apps/contacts/ajax/addproperty.php +++ b/apps/contacts/ajax/addproperty.php @@ -113,7 +113,7 @@ foreach ($parameters as $key=>$element) { } $checksum = md5($vcard->children[$line]->serialize()); -if(!OC_Contacts_VCard::edit($id,$vcard->serialize())) { +if(!OC_Contacts_VCard::edit($id,$vcard)) { OC_JSON::error(array('data' => array('message' => OC_Contacts_App::$l10n->t('Error adding contact property.')))); OC_Log::write('contacts','ajax/addproperty.php: Error updating contact property: '.$name, OC_Log::ERROR); exit(); diff --git a/apps/contacts/ajax/deleteproperty.php b/apps/contacts/ajax/deleteproperty.php index a9afffaad4..ab0958cac5 100644 --- a/apps/contacts/ajax/deleteproperty.php +++ b/apps/contacts/ajax/deleteproperty.php @@ -39,7 +39,7 @@ if(is_null($line)){ unset($vcard->children[$line]); -if(!OC_Contacts_VCard::edit($id,$vcard->serialize())) { +if(!OC_Contacts_VCard::edit($id,$vcard)) { OC_JSON::error(array('data' => array('message' => OC_Contacts_App::$l10n->t('Error deleting contact property.')))); OC_Log::write('contacts','ajax/deleteproperty.php: Error deleting contact property', OC_Log::ERROR); exit(); diff --git a/apps/contacts/ajax/savecrop.php b/apps/contacts/ajax/savecrop.php index 1a84f6fdfa..ffbfaeb6e3 100644 --- a/apps/contacts/ajax/savecrop.php +++ b/apps/contacts/ajax/savecrop.php @@ -95,7 +95,7 @@ if(file_exists($tmp_path)) { OC_Log::write('contacts','savecrop.php: files: Adding PHOTO property.', OC_Log::DEBUG); $card->addProperty('PHOTO', $image->__toString(), array('ENCODING' => 'b', 'TYPE' => $image->mimeType())); } - if(!OC_Contacts_VCard::edit($id,$card->serialize())) { + if(!OC_Contacts_VCard::edit($id,$card)) { bailOut('Error saving contact.'); } unlink($tmpfname); diff --git a/apps/contacts/ajax/saveproperty.php b/apps/contacts/ajax/saveproperty.php index 6f8366243f..db209fedfc 100644 --- a/apps/contacts/ajax/saveproperty.php +++ b/apps/contacts/ajax/saveproperty.php @@ -122,7 +122,7 @@ switch($element) { $checksum = md5($vcard->children[$line]->serialize()); debug('New checksum: '.$checksum); -if(!OC_Contacts_VCard::edit($id,$vcard->serialize())) { +if(!OC_Contacts_VCard::edit($id,$vcard)) { OC_JSON::error(array('data' => array('message' => OC_Contacts_App::$l10n->t('Error updating contact property.')))); OC_Log::write('contacts','ajax/setproperty.php: Error updating contact property: '.$value, OC_Log::ERROR); exit(); diff --git a/apps/contacts/ajax/setproperty.php b/apps/contacts/ajax/setproperty.php index f9e2a8e864..8e07b4a8f1 100644 --- a/apps/contacts/ajax/setproperty.php +++ b/apps/contacts/ajax/setproperty.php @@ -80,7 +80,7 @@ foreach($missingparameters as $i){ // NOTE: This checksum is not used..? $checksum = md5($vcard->children[$line]->serialize()); -if(!OC_Contacts_VCard::edit($id,$vcard->serialize())) { +if(!OC_Contacts_VCard::edit($id,$vcard)) { OC_JSON::error(array('data' => array('message' => $l->t('Error updating contact property.')))); OC_Log::write('contacts','ajax/setproperty.php: Error updating contact property: '.$value, OC_Log::ERROR); exit(); diff --git a/apps/contacts/import.php b/apps/contacts/import.php index 4638bf0d73..04cfc397d5 100644 --- a/apps/contacts/import.php +++ b/apps/contacts/import.php @@ -97,11 +97,15 @@ if(is_writable('import_tmp/')){ fclose($progressfopen); } if(count($parts) == 1){ - OC_Contacts_VCard::add($id, $file); -}else{ - foreach($importready as $import){ - OC_Contacts_VCard::add($id, $import); + $importready = array($file); +} +foreach($importready as $import){ + $card = OC_VObject::parse($import); + if (!$card) { + OC_Log::write('contacts','Import: skipping card. Error parsing VCard: '.$import, OC_Log::ERROR); + continue; // Ditch cards that can't be parsed by Sabre. } + OC_Contacts_VCard::add($id, $card); } //done the import if(is_writable('import_tmp/')){ @@ -113,4 +117,4 @@ sleep(3); if(is_writable('import_tmp/')){ unlink($progressfile); } -OC_JSON::success(); \ No newline at end of file +OC_JSON::success(); diff --git a/apps/contacts/lib/app.php b/apps/contacts/lib/app.php index ce52df4b75..e8c3087c8a 100644 --- a/apps/contacts/lib/app.php +++ b/apps/contacts/lib/app.php @@ -92,7 +92,7 @@ class OC_Contacts_App { OC_Log::write('contacts','getContactVCard, found FN field: '.$vcard->__get('FN'), OC_Log::DEBUG); $n = implode(';', array_reverse(array_slice(explode(' ', $vcard->__get('FN')), 0, 2))).';;;'; $vcard->setString('N', $n); - OC_Contacts_VCard::edit( $id, $vcard->serialize()); + OC_Contacts_VCard::edit( $id, $vcard); } else { // Else just add an empty 'N' field :-P $vcard->setString('N', 'Unknown;Name;;;'); } diff --git a/apps/contacts/lib/vcard.php b/apps/contacts/lib/vcard.php index 0b8d95a2d9..9324f158cc 100644 --- a/apps/contacts/lib/vcard.php +++ b/apps/contacts/lib/vcard.php @@ -217,31 +217,35 @@ class OC_Contacts_VCard{ /** * @brief Adds a card - * @param integer $id Addressbook id - * @param string $data vCard file - * @return insertid on success or null if card is not parseable. + * @param integer $aid Addressbook id + * @param OC_VObject $card vCard file + * @param string $uri the uri of the card, default based on the UID + * @return insertid on success or null if no card. */ - public static function add($id,$data){ - $fn = null; - - $card = OC_VObject::parse($data); - if(!is_null($card)){ - self::updateValuesFromAdd($card); - $data = $card->serialize(); - } - else{ - OC_Log::write('contacts','OC_Contacts_VCard::add. Error parsing VCard: '.$data,OC_Log::ERROR); - return null; // Ditch cards that can't be parsed by Sabre. + public static function add($aid, $card, $uri=null){ + if(is_null($card)){ + OC_Log::write('contacts','OC_Contacts_VCard::add. No vCard supplied', OC_Log::ERROR); + return null; }; + self::updateValuesFromAdd($card); + $fn = $card->getAsString('FN'); - $uid = $card->getAsString('UID'); - $uri = $uid.'.vcf'; + if (empty($fn)) { + $fn = null; + } + + if (!$uri) { + $uid = $card->getAsString('UID'); + $uri = $uid.'.vcf'; + } + + $data = $card->serialize(); $stmt = OC_DB::prepare( 'INSERT INTO *PREFIX*contacts_cards (addressbookid,fullname,carddata,uri,lastmodified) VALUES(?,?,?,?,?)' ); - $result = $stmt->execute(array($id,$fn,$data,$uri,time())); + $result = $stmt->execute(array($aid,$fn,$data,$uri,time())); $newid = OC_DB::insertid('*PREFIX*contacts_cards'); - OC_Contacts_Addressbook::touch($id); + OC_Contacts_Addressbook::touch($aid); return $newid; } @@ -255,49 +259,31 @@ class OC_Contacts_VCard{ */ public static function addFromDAVData($id,$uri,$data){ $card = OC_VObject::parse($data); - if(!is_null($card)){ - self::updateValuesFromAdd($card); - $data = $card->serialize(); - } else { - OC_Log::write('contacts','OC_Contacts_VCard::addFromDAVData. Error parsing VCard: '.$data, OC_Log::ERROR); - return null; // Ditch cards that can't be parsed by Sabre. - }; - $fn = $card->getAsString('FN'); - - $stmt = OC_DB::prepare( 'INSERT INTO *PREFIX*contacts_cards (addressbookid,fullname,carddata,uri,lastmodified) VALUES(?,?,?,?,?)' ); - $result = $stmt->execute(array($id,$fn,$data,$uri,time())); - $newid = OC_DB::insertid('*PREFIX*contacts_cards'); - - OC_Contacts_Addressbook::touch($id); - - return $newid; + return self::add($id, $data, $uri); } /** * @brief edits a card * @param integer $id id of card - * @param string $data vCard file + * @param OC_VObject $card vCard file * @return boolean */ - public static function edit($id, $data){ + public static function edit($id, OC_VObject $card){ $oldcard = self::find($id); - $fn = null; - $card = OC_VObject::parse($data); - if(!is_null($card)){ - foreach($card->children as $property){ - if($property->name == 'FN'){ - $fn = $property->value; - break; - } - } - } else { + if(is_null($card)) { return false; } + + $fn = $card->getAsString('FN'); + if (empty($fn)) { + $fn = null; + } + $now = new DateTime; $card->setString('REV', $now->format(DateTime::W3C)); - $data = $card->serialize(); + $data = $card->serialize(); $stmt = OC_DB::prepare( 'UPDATE *PREFIX*contacts_cards SET fullname = ?,carddata = ?, lastmodified = ? WHERE id = ?' ); $result = $stmt->execute(array($fn,$data,time(),$id)); @@ -315,27 +301,8 @@ class OC_Contacts_VCard{ */ public static function editFromDAVData($aid,$uri,$data){ $oldcard = self::findWhereDAVDataIs($aid,$uri); - - $fn = null; $card = OC_VObject::parse($data); - if(!is_null($card)){ - foreach($card->children as $property){ - if($property->name == 'FN'){ - $fn = $property->value; - break; - } - } - } - $now = new DateTime; - $card->setString('REV', $now->format(DateTime::W3C)); - $data = $card->serialize(); - - $stmt = OC_DB::prepare( 'UPDATE *PREFIX*contacts_cards SET fullname = ?,carddata = ?, lastmodified = ? WHERE id = ?' ); - $result = $stmt->execute(array($fn,$data,time(),$oldcard['id'])); - - OC_Contacts_Addressbook::touch($oldcard['addressbookid']); - - return true; + return self::edit($oldcard['id'], $card); } /** @@ -351,14 +318,6 @@ class OC_Contacts_VCard{ return true; } - /** - * @brief Creates a UID - * @return string - */ - public static function createUID(){ - return substr(md5(rand().time()),0,10); - } - /** * @brief deletes a card with the data provided by sabredav * @param integer $aid Addressbook id From d8cfe77ba5348d29a9e2b046e2c7efc1dd4758cb Mon Sep 17 00:00:00 2001 From: Bart Visscher Date: Wed, 7 Mar 2012 21:29:23 +0100 Subject: [PATCH 041/132] Contacts: small fixes and cleanups --- apps/calendar/lib/object.php | 11 +---------- apps/contacts/ajax/loadphoto.php | 6 ++---- apps/contacts/lib/vcard.php | 5 +++++ 3 files changed, 8 insertions(+), 14 deletions(-) diff --git a/apps/calendar/lib/object.php b/apps/calendar/lib/object.php index b84e575bc8..e0c0e83d5d 100644 --- a/apps/calendar/lib/object.php +++ b/apps/calendar/lib/object.php @@ -96,8 +96,7 @@ class OC_Calendar_Object{ list($type,$startdate,$enddate,$summary,$repeating,$uid) = self::extractData($object); if(is_null($uid)){ - $uid = self::createUID(); - $object->add('UID',$uid); + $object->setUID(); $data = $object->serialize(); } @@ -208,14 +207,6 @@ class OC_Calendar_Object{ return true; } - /** - * @brief Creates a UID - * @return string - */ - protected static function createUID(){ - return substr(md5(rand().time()),0,10); - } - /** * @brief Extracts data from a vObject-Object * @param Sabre_VObject $object diff --git a/apps/contacts/ajax/loadphoto.php b/apps/contacts/ajax/loadphoto.php index 358e046942..1f4cde0b53 100644 --- a/apps/contacts/ajax/loadphoto.php +++ b/apps/contacts/ajax/loadphoto.php @@ -18,8 +18,6 @@ * You should have received a copy of the GNU Affero General Public * License along with this library. If not, see . * - * TODO: Translatable strings. - * Remember to delete tmp file at some point. */ // Init owncloud require_once('../../../lib/base.php'); @@ -33,7 +31,7 @@ OC_JSON::checkAppEnabled('contacts'); function bailOut($msg) { OC_JSON::error(array('data' => array('message' => $msg))); - OC_Log::write('contacts','ajax/savecrop.php: '.$msg, OC_Log::DEBUG); + OC_Log::write('contacts','ajax/loadphoto.php: '.$msg, OC_Log::DEBUG); exit(); } @@ -42,7 +40,7 @@ $image = null; $id = isset($_GET['id']) ? $_GET['id'] : ''; if($id == '') { - bailOut('Missing contact id.'); + bailOut(OC_Contacts_App::$l10n->t('Missing contact id.')); } $tmpl = new OC_TEMPLATE("contacts", "part.contactphoto"); diff --git a/apps/contacts/lib/vcard.php b/apps/contacts/lib/vcard.php index 9324f158cc..eade8859e7 100644 --- a/apps/contacts/lib/vcard.php +++ b/apps/contacts/lib/vcard.php @@ -174,6 +174,9 @@ class OC_Contacts_VCard{ if($property->name == 'UID'){ $uid = $property->value; } + if($property->name == 'ORG'){ + $org = $property->value; + } if($property->name == 'EMAIL' && is_null($email)){ // only use the first email as substitute for missing N or FN. $email = $property->value; } @@ -184,6 +187,8 @@ class OC_Contacts_VCard{ $fn = join(' ', array_reverse(array_slice(explode(';', $n), 0, 2))); } elseif($email) { $fn = $email; + } elseif($org) { + $fn = $org; } else { $fn = 'Unknown Name'; } From 340320625e8da301e4c03752143db6d4837ca545 Mon Sep 17 00:00:00 2001 From: Bart Visscher Date: Wed, 7 Mar 2012 21:50:55 +0100 Subject: [PATCH 042/132] Contacts: Add UI for categories --- apps/contacts/ajax/saveproperty.php | 1 + apps/contacts/index.php | 2 + apps/contacts/js/contacts.js | 10 +++- apps/contacts/js/jquery.multi-autocomplete.js | 47 +++++++++++++++++++ apps/contacts/lib/app.php | 4 ++ apps/contacts/templates/index.php | 1 + apps/contacts/templates/part.contact.php | 3 ++ 7 files changed, 67 insertions(+), 1 deletion(-) create mode 100644 apps/contacts/js/jquery.multi-autocomplete.js diff --git a/apps/contacts/ajax/saveproperty.php b/apps/contacts/ajax/saveproperty.php index db209fedfc..c1d5cebfd0 100644 --- a/apps/contacts/ajax/saveproperty.php +++ b/apps/contacts/ajax/saveproperty.php @@ -92,6 +92,7 @@ switch($element) { case 'N': case 'ORG': case 'NICKNAME': + case 'CATEGORIES': debug('Setting string:'.$name.' '.$value); $vcard->setString($name, $value); break; diff --git a/apps/contacts/index.php b/apps/contacts/index.php index 0a21ddd04b..b8dfc1b770 100644 --- a/apps/contacts/index.php +++ b/apps/contacts/index.php @@ -48,6 +48,7 @@ OC_Util::addScript('contacts','contacts'); OC_Util::addScript('contacts','jquery.combobox'); OC_Util::addScript('contacts','jquery.inview'); OC_Util::addScript('contacts','jquery.Jcrop'); +OC_Util::addScript('contacts','jquery.multi-autocomplete'); OC_Util::addStyle('','jquery.multiselect'); //OC_Util::addStyle('contacts','styles'); OC_Util::addStyle('contacts','jquery.combobox'); @@ -58,6 +59,7 @@ $tmpl = new OC_Template( "contacts", "index", "user" ); $tmpl->assign('uploadMaxFilesize', $maxUploadFilesize); $tmpl->assign('uploadMaxHumanFilesize', OC_Helper::humanFileSize($maxUploadFilesize)); $tmpl->assign('property_types',$property_types); +$tmpl->assign('categories',OC_Contacts_App::getCategories()); $tmpl->assign('phone_types',$phone_types); $tmpl->assign('addressbooks', $addressbooks); $tmpl->assign('contacts', $contacts); diff --git a/apps/contacts/js/contacts.js b/apps/contacts/js/contacts.js index 94876f5cd0..0c63b5fcb7 100644 --- a/apps/contacts/js/contacts.js +++ b/apps/contacts/js/contacts.js @@ -223,6 +223,7 @@ Contacts={ click: function() { $(this).dialog('close'); } } ] ); + $('#categories').multiple_autocomplete({source: categories}); Contacts.UI.loadListHandlers(); }, Card:{ @@ -371,7 +372,7 @@ Contacts={ this.loadSingleProperties(); }, loadSingleProperties:function() { - var props = ['BDAY', 'NICKNAME', 'ORG']; + var props = ['BDAY', 'NICKNAME', 'ORG', 'CATEGORIES']; // Clear all elements $('#ident .propertycontainer').each(function(){ if(props.indexOf($(this).data('element')) > -1) { @@ -407,6 +408,12 @@ Contacts={ $('#contact_identity').find('#org_label').show(); $('#contact_identity').find('#org_value').show(); break; + case 'CATEGORIES': + $('#contact_identity').find('#categories').val(value); + $('#contact_identity').find('#categories_value').data('checksum', checksum); + $('#contact_identity').find('#categories_label').show(); + $('#contact_identity').find('#categories_value').show(); + break; } } else { $('#contacts_propertymenu a[data-type="'+props[prop]+'"]').parent().show(); @@ -596,6 +603,7 @@ Contacts={ case 'NICKNAME': case 'ORG': case 'BDAY': + case 'CATEGORIES': $('dl dt[data-element="'+type+'"],dd[data-element="'+type+'"]').show(); $('#contacts_propertymenu a[data-type="'+type+'"]').parent().hide(); break; diff --git a/apps/contacts/js/jquery.multi-autocomplete.js b/apps/contacts/js/jquery.multi-autocomplete.js new file mode 100644 index 0000000000..4be8d901c9 --- /dev/null +++ b/apps/contacts/js/jquery.multi-autocomplete.js @@ -0,0 +1,47 @@ +/** + * Inspired by http://jqueryui.com/demos/autocomplete/#multiple + */ + +(function( $ ) { + $.widget('ui.multiple_autocomplete', { + _create: function() { + function split( val ) { + return val.split( /,\s*/ ); + } + function extractLast( term ) { + return split( term ).pop(); + } + //console.log('_create: ' + this.options['id']); + var self = this; + this.element.bind( "keydown", function( event ) { + if ( event.keyCode === $.ui.keyCode.TAB && + $( this ).data( "autocomplete" ).menu.active ) { + event.preventDefault(); + } + }) + .autocomplete({ + minLength: 0, + source: function( request, response ) { + // delegate back to autocomplete, but extract the last term + response( $.ui.autocomplete.filter( + self.options.source, extractLast( request.term ) ) ); + }, + focus: function() { + // prevent value inserted on focus + return false; + }, + select: function( event, ui ) { + var terms = split( this.value ); + // remove the current input + terms.pop(); + // add the selected item + terms.push( ui.item.value ); + // add placeholder to get the comma-and-space at the end + terms.push( "" ); + this.value = terms.join( ", " ); + return false; + } + }); + }, + }); +})( jQuery ); diff --git a/apps/contacts/lib/app.php b/apps/contacts/lib/app.php index 1fa441475d..cc33c73300 100644 --- a/apps/contacts/lib/app.php +++ b/apps/contacts/lib/app.php @@ -155,6 +155,10 @@ class OC_Contacts_App { } } + public static function getCategories() { + return self::$categories->categories(); + } + public static function setLastModifiedHeader($contact) { $rev = $contact->getAsString('REV'); if ($rev) { diff --git a/apps/contacts/templates/index.php b/apps/contacts/templates/index.php index e81597f23d..efd797e25c 100644 --- a/apps/contacts/templates/index.php +++ b/apps/contacts/templates/index.php @@ -1,5 +1,6 @@
      diff --git a/apps/contacts/templates/part.contact.php b/apps/contacts/templates/part.contact.php index 5be20964f4..783dc46907 100644 --- a/apps/contacts/templates/part.contact.php +++ b/apps/contacts/templates/part.contact.php @@ -13,6 +13,7 @@ $id = isset($_['id']) ? $_['id'] : '';
    • t('Phone'); ?>
    • t('Email'); ?>
    • t('Address'); ?>
    • +
    • t('Categories'); ?>
    • @@ -53,6 +54,8 @@ $id = isset($_['id']) ? $_['id'] : ''; + + From 91d85e9b1640e9d62707cd1c232c8c7a9fc8b9c3 Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Wed, 7 Mar 2012 22:57:37 +0100 Subject: [PATCH 043/132] Use OC.dialogs. --- apps/contacts/js/contacts.js | 110 +++++++++++++---------------------- 1 file changed, 39 insertions(+), 71 deletions(-) diff --git a/apps/contacts/js/contacts.js b/apps/contacts/js/contacts.js index 626672cf78..d86842a431 100644 --- a/apps/contacts/js/contacts.js +++ b/apps/contacts/js/contacts.js @@ -19,9 +19,9 @@ Categories={ var response = jQuery.parseJSON(response); console.log('status: ' + status + ', response: ' + response + ', response.status:' + response.status); if(response.status == 'error'){ - alert(response.data.message); + OC.dialogs.alert(response.data.message, 'Error'); } else { - alert(response); + OC.dialogs.alert(response, 'Error'); } } catch(e) { $('#edit_categories_dialog').dialog({ @@ -71,7 +71,7 @@ Categories={ if(jsondata.status == 'success'){ Categories._update(jsondata.data.categories); } else { - alert(jsondata.data.message); + OC.dialogs.alert(jsondata.data.message, 'Error'); } }); }, @@ -81,7 +81,7 @@ Categories={ if(jsondata.status == 'success'){ Categories._update(jsondata.data.categories); } else { - alert(jsondata.data.message); + OC.dialogs.alert(jsondata.data.message, 'Error'); } }); return false; @@ -92,7 +92,7 @@ Categories={ if(jsondata.status == 'success'){ Categories._update(jsondata.data.categories); } else { - alert(jsondata.data.message); + OC.dialogs.alert(jsondata.data.message, 'Error'); } }); }, @@ -112,13 +112,13 @@ Categories={ Contacts={ UI:{ notImplemented:function() { - Contacts.UI.messageBox(t('contacts', 'Not implemented'), t('contacts', 'Sorry, this functionality has not been implemented yet')); + OC.dialogs.alert(t('contacts', 'Sorry, this functionality has not been implemented yet'), t('contacts', 'Not implemented')); }, searchOSM:function(obj) { var adr = Contacts.UI.propertyContainerFor(obj).find('.adr').val(); console.log('adr 1: ' + adr); if(adr == undefined) { - Contacts.UI.messageBox(t('contacts', 'Error'), t('contacts', 'Couldn\'t get a valid address.')); + OC.dialogs.alert(t('contacts', 'Couldn\'t get a valid address.'), t('contacts', 'Error')); return; } // FIXME: I suck at regexp. /Tanghus @@ -151,7 +151,7 @@ Contacts={ mailTo:function(obj) { var adr = Contacts.UI.propertyContainerFor($(obj)).find('input[type="email"]').val().trim(); if(adr == '') { - Contacts.UI.messageBox(t('contacts', 'Error'), t('contacts', 'Please enter an email address.')); + OC.dialogs.alert(t('contacts', 'Please enter an email address.'), t('contacts', 'Error')); return; } window.location.href='mailto:' + adr; @@ -214,38 +214,6 @@ Contacts={ $('#carddav_url').show(); $('#carddav_url_close').show(); }, - messageBox:function(title, msg) { - if(msg.toLowerCase().indexOf('auth') != -1) { - // fugly hack, I know - alert(msg); - } - if($('#messagebox').dialog('isOpen') == true){ - // NOTE: Do we ever get here? - $('#messagebox').dialog('moveToTop'); - }else{ - $('#dialog_holder').load(OC.filePath('contacts', 'ajax', 'messagebox.php'), function(jsondata){ - if(jsondata.status != 'error'){ - $('#messagebox').dialog( - { - autoOpen: true, - title: title, - buttons: [{ - text: "Ok", - click: function() { $(this).dialog("close"); } - }], - close: function(event, ui) { - $(this).dialog('destroy').remove(); - }, - open: function(event, ui) { - $('#messagebox_msg').html(msg); - } - }); - } else { - alert(jsondata.data.message); - } - }); - }; - }, loadListHandlers:function() { //$('.add,.delete').hide(); $('.globe,.mail,.delete,.edit').tipsy(); @@ -360,12 +328,12 @@ Contacts={ if(jsondata.status == 'success'){ Contacts.UI.Card.loadContact(jsondata.data); } else{ - Contacts.UI.messageBox(t('contacts', 'Error'), jsondata.data.message); + OC.dialogs.alert(jsondata.data.message, t('contacts', 'Error')); } }); } } else{ - Contacts.UI.messageBox(t('contacts', 'Error'), jsondata.data.message); + OC.dialogs.alert(jsondata.data.message, t('contacts', 'Error')); } }); } @@ -377,7 +345,7 @@ Contacts={ $('#rightcontent').data('id',''); $('#rightcontent').html(jsondata.data.page); } else { - Contacts.UI.messageBox(t('contacts', 'Error'), jsondata.data.message); + OC.dialogs.alert(jsondata.data.message, t('contacts', 'Error')); } }); } @@ -417,7 +385,7 @@ Contacts={ } else{ - Contacts.UI.messageBox(t('contacts', 'Error'), jsondata.data.message); + OC.dialogs.alert(jsondata.data.message, t('contacts', 'Error')); //alert(jsondata.data.message); } }); @@ -426,7 +394,7 @@ Contacts={ // TODO: Add to contacts list. } else{ - Contacts.UI.messageBox(t('contacts', 'Error'), jsondata.data.message); + OC.dialogs.alert(jsondata.data.message, t('contacts', 'Error')); //alert(jsondata.data.message); } }); @@ -452,13 +420,13 @@ Contacts={ $('#rightcontent').html(jsondata.data.page); } else{ - Contacts.UI.messageBox(t('contacts', 'Error'), jsondata.data.message); + OC.dialogs.alert(jsondata.data.message, t('contacts', 'Error')); } }); } } else{ - Contacts.UI.messageBox(t('contacts', 'Error'), jsondata.data.message); + OC.dialogs.alert(jsondata.data.message, t('contacts', 'Error')); //alert(jsondata.data.message); } }); @@ -604,7 +572,7 @@ Contacts={ console.log('Setting checksum: ' + jsondata.data.checksum); $('#categories_value').data('checksum', jsondata.data.checksum); } else { - Contacts.UI.messageBox(t('contacts', 'Error'), jsondata.data.message); + OC.dialogs.alert(jsondata.data.message, t('contacts', 'Error')); } }); }, @@ -633,7 +601,7 @@ Contacts={ $('#rightcontent').html(jsondata.data.page); Contacts.UI.Card.editName(); } else { - Contacts.UI.messageBox(t('contacts', 'Error'), jsondata.data.message); + OC.dialogs.alert(jsondata.data.message, t('contacts', 'Error')); //alert(jsondata.data.message); } }); @@ -676,7 +644,7 @@ Contacts={ return false; } if($(obj).hasClass('nonempty') && $(obj).val().trim() == '') { - Contacts.UI.messageBox(t('contacts', 'Error'), t('contacts', 'This property has to be non-empty.')); + OC.dialogs.alert(t('contacts', 'This property has to be non-empty.'), t('contacts', 'Error')); return false; } container = $(obj).parents('.propertycontainer').first(); // get the parent holding the metadata. @@ -705,7 +673,7 @@ Contacts={ return true; } else{ - Contacts.UI.messageBox(t('contacts', 'Error'), jsondata.data.message); + OC.dialogs.alert(jsondata.data.message, t('contacts', 'Error')); Contacts.UI.loading(container, false); $(obj).removeAttr('disabled'); return false; @@ -724,7 +692,7 @@ Contacts={ return true; } else{ - Contacts.UI.messageBox(t('contacts', 'Error'), jsondata.data.message); + OC.dialogs.alert(jsondata.data.message, t('contacts', 'Error')); Contacts.UI.loading(container, false); $(obj).removeAttr('disabled'); return false; @@ -792,13 +760,13 @@ Contacts={ $('#contacts_propertymenu a[data-type="'+proptype+'"]').parent().show(); Contacts.UI.loading(obj, false); } else { - Contacts.UI.messageBox(t('contacts', 'Error'), t('contacts', '\'deleteProperty\' called without type argument. Please report at bugs.owncloud.org')); + OC.dialogs.alert(t('contacts', '\'deleteProperty\' called without type argument. Please report at bugs.owncloud.org'), t('contacts', 'Error')); Contacts.UI.loading(obj, false); } } else{ Contacts.UI.loading(obj, false); - Contacts.UI.messageBox(t('contacts', 'Error'), jsondata.data.message); + OC.dialogs.alert(jsondata.data.message, t('contacts', 'Error')); } }); } else { // Property hasn't been saved so there's nothing to delete. @@ -813,7 +781,7 @@ Contacts={ $('#contacts_propertymenu a[data-type="'+proptype+'"]').parent().show(); Contacts.UI.loading(obj, false); } else { - Contacts.UI.messageBox(t('contacts', 'Error'), t('contacts', '\'deleteProperty\' called without type argument. Please report at bugs.owncloud.org')); + OC.dialogs.alert(t('contacts', '\'deleteProperty\' called without type argument. Please report at bugs.owncloud.org'), t('contacts', 'Error')); } } }, @@ -1034,7 +1002,7 @@ Contacts={ }, uploadPhoto:function(filelist) { if(!filelist) { - Contacts.UI.messageBox(t('contacts', 'Error'), t('contacts','No files selected for upload.')); + OC.dialogs.alert(t('contacts','No files selected for upload.'), t('contacts', 'Error')); return; } //var file = filelist.item(0); @@ -1043,7 +1011,7 @@ Contacts={ var form = $('#file_upload_form'); var totalSize=0; if(file.size > $('#max_upload').val()){ - Contacts.UI.messageBox(t('Upload too large'), t('contacts','The file you are trying to upload exceed the maximum size for file uploads on this server.')); + 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(){ @@ -1052,7 +1020,7 @@ Contacts={ Contacts.UI.Card.editPhoto(response.data.id, response.data.tmp); //alert('File: ' + file.tmp + ' ' + file.name + ' ' + file.mime); }else{ - Contacts.UI.messageBox(t('contacts', 'Error'), response.data.message); + OC.dialogs.alert(response.data.message, t('contacts', 'Error')); } }); form.submit(); @@ -1066,7 +1034,7 @@ Contacts={ $('#contacts_details_photo_wrapper').html(jsondata.data.page); } else{ - Contacts.UI.messageBox(jsondata.data.message); + OC.dialogs.alert(jsondata.data.message, t('contacts', 'Error')); } }); $('#file_upload_form').show(); @@ -1085,7 +1053,7 @@ Contacts={ $('#edit_photo_dialog_img').html(jsondata.data.page); } else{ - Contacts.UI.messageBox(jsondata.data.message); + OC.dialogs.alert(jsondata.data.message, t('contacts', 'Error')); } }); if($('#edit_photo_dialog').dialog('isOpen') == true){ @@ -1104,7 +1072,7 @@ Contacts={ // load cropped photo. $('#contacts_details_photo_wrapper').html(response.data.page); }else{ - Contacts.UI.messageBox(t('contacts','Error'), response.data.message); + OC.dialogs.alert(response.data.message, t('contacts', 'Error')); } }); $('#contacts [data-id="'+this.id+'"]').find('a').css('background','url(thumbnail.php?id='+this.id+'&refresh=1'+Math.random()+') no-repeat'); @@ -1244,7 +1212,7 @@ Contacts={ Contacts.UI.Contacts.update(); Contacts.UI.Addressbooks.overview(); } else { - Contacts.UI.messageBox(t('contacts', 'Error'), jsondata.data.message); + OC.dialogs.alert(jsondata.data.message, t('contacts', 'Error')); //alert('Error: ' + data.message); } }); @@ -1259,7 +1227,7 @@ Contacts={ var description = $("#description_"+bookid).val(); if(displayname.length == 0) { - Contacts.UI.messageBox(t('contacts', 'Error'), t('contacts', 'Displayname cannot be empty.')); + OC.dialogs.alert(t('contacts', 'Displayname cannot be empty.'), t('contacts', 'Error')); return false; } var url; @@ -1274,7 +1242,7 @@ Contacts={ $(button).closest('tr').prev().html(jsondata.page).show().next().remove(); Contacts.UI.Contacts.update(); } else { - Contacts.UI.messageBox(t('contacts', 'Error'), jsondata.data.message); + OC.dialogs.alert(jsondata.data.message, t('contacts', 'Error')); } }); }, @@ -1294,7 +1262,7 @@ Contacts={ Contacts.UI.Card.update(); } else{ - Contacts.UI.messageBox(t('contacts', 'Error'),jsondata.data.message); + OC.dialogs.alert(jsondata.data.message, t('contacts', 'Error')); //alert(jsondata.data.message); } }); @@ -1344,7 +1312,7 @@ $(document).ready(function(){ Contacts.UI.Card.loadContact(jsondata.data); } else{ - Contacts.UI.messageBox(t('contacts', 'Error'), jsondata.data.message); + OC.dialogs.alert(jsondata.data.message, t('contacts', 'Error')); //alert(jsondata.data.message); } }); @@ -1443,17 +1411,17 @@ $(document).ready(function(){ var file = files[0]; console.log('size: '+file.size); if(file.size > $('#max_upload').val()){ - Contacts.UI.messageBox(t('contacts','Upload too large'), t('contacts','The file you are trying to upload exceed the maximum size for file uploads on this server.')); + 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')); return; } if (file.type.indexOf("image") != 0) { - Contacts.UI.messageBox(t('contacts','Wrong file type'), t('contacts','Only image files can be used as profile picture.')); + OC.dialogs.alert(t('contacts','Only image files can be used as profile picture.'), t('contacts','Wrong file type')); return; } var xhr = new XMLHttpRequest(); if (!xhr.upload) { - Contacts.UI.messageBox(t('contacts', 'Error'), t('contacts', 'Your browser doesn\'t support AJAX upload. Please click on the profile picture to select a photo to upload.')) + OC.dialogs.alert(t('contacts', 'Your browser doesn\'t support AJAX upload. Please click on the profile picture to select a photo to upload.'), t('contacts', 'Error')) } fileUpload = xhr.upload, xhr.onreadystatechange = function() { @@ -1463,11 +1431,11 @@ $(document).ready(function(){ if(xhr.status == 200) { Contacts.UI.Card.editPhoto(response.data.id, response.data.tmp); } else { - Contacts.UI.messageBox(t('contacts', 'Error'), xhr.status + ': ' + xhr.responseText); + OC.dialogs.alert(xhr.status + ': ' + xhr.responseText, t('contacts', 'Error')); } } else { //alert(xhr.responseText); - Contacts.UI.messageBox(t('contacts', 'Error'), response.data.message); + OC.dialogs.alert(response.data.message, t('contacts', 'Error')); } // stop loading indicator //$('#contacts_details_photo_progress').hide(); From 700a120c225f056070f1c5601ca91f88b3bbe870 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Thu, 8 Mar 2012 15:47:49 +0100 Subject: [PATCH 044/132] fix write hook for gallery --- apps/gallery/lib/hooks_handlers.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/gallery/lib/hooks_handlers.php b/apps/gallery/lib/hooks_handlers.php index 3c101b1f8a..480e41a8bf 100644 --- a/apps/gallery/lib/hooks_handlers.php +++ b/apps/gallery/lib/hooks_handlers.php @@ -68,7 +68,7 @@ class OC_Gallery_Hooks_Handlers { if (!self::isPhoto($fullpath)) return; - $path = substr($fullpath, 0, strrpos($fullpath, '/')); + $path = dirname($fullpath); if (!self::pathInRoot($path)) return; OC_Gallery_Scanner::scanDir($path, $albums); From 8495e1a63e20e9cae0f1c1835de558606d1ecfc4 Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Wed, 22 Feb 2012 11:25:45 +0100 Subject: [PATCH 045/132] Add missing file. --- apps/contacts/ajax/loadcard.php | 59 +++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 apps/contacts/ajax/loadcard.php diff --git a/apps/contacts/ajax/loadcard.php b/apps/contacts/ajax/loadcard.php new file mode 100644 index 0000000000..037fe2a6df --- /dev/null +++ b/apps/contacts/ajax/loadcard.php @@ -0,0 +1,59 @@ + + * + * 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 . + * + */ + +// Init owncloud +require_once('../../../lib/base.php'); +function bailOut($msg) { + OC_JSON::error(array('data' => array('message' => $msg))); + OC_Log::write('contacts','ajax/loadcard.php: '.$msg, OC_Log::DEBUG); + exit(); +} +function debug($msg) { + OC_Log::write('contacts','ajax/loadcard.php: '.$msg, OC_Log::DEBUG); +} +// foreach ($_POST as $key=>$element) { +// debug('_POST: '.$key.'=>'.$element); +// } + +// Check if we are a user +OC_JSON::checkLoggedIn(); +OC_JSON::checkAppEnabled('contacts'); + +$upload_max_filesize = OC_Helper::computerFileSize(ini_get('upload_max_filesize')); +$post_max_size = OC_Helper::computerFileSize(ini_get('post_max_size')); +$maxUploadFilesize = min($upload_max_filesize, $post_max_size); + +$freeSpace=OC_Filesystem::free_space('/'); +$freeSpace=max($freeSpace,0); +$maxUploadFilesize = min($maxUploadFilesize ,$freeSpace); +$adr_types = OC_Contacts_App::getTypesOfProperty('ADR'); +$phone_types = OC_Contacts_App::getTypesOfProperty('TEL'); + +$tmpl = new OC_Template('contacts','part.contact'); +$tmpl->assign('uploadMaxFilesize', $maxUploadFilesize); +$tmpl->assign('uploadMaxHumanFilesize', OC_Helper::humanFileSize($maxUploadFilesize)); +$tmpl->assign('adr_types',$adr_types); +$tmpl->assign('phone_types',$phone_types); +$tmpl->assign('id',''); +$page = $tmpl->fetchPage(); + +OC_JSON::success(array('data' => array( 'page' => $page ))); From bc5d9f58684acad4602bc7d43170b040a15f6dd5 Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Fri, 9 Mar 2012 07:36:05 +0100 Subject: [PATCH 046/132] Parses malformed N fields a bit more tolerantly. Thanks to nibbler for the patch :-) --- apps/contacts/js/contacts.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/contacts/js/contacts.js b/apps/contacts/js/contacts.js index 94876f5cd0..4ede2ff433 100644 --- a/apps/contacts/js/contacts.js +++ b/apps/contacts/js/contacts.js @@ -424,11 +424,11 @@ Contacts={ } else { narray = this.data.N[0]['value']; } - this.famname = narray[0]; - this.givname = narray[1]; - this.addname = narray[2]; - this.honpre = narray[3]; - this.honsuf = narray[4]; + this.famname = narray[0] || ''; + this.givname = narray[1] || ''; + this.addname = narray[2] || ''; + this.honpre = narray[3] || ''; + this.honsuf = narray[4] || ''; if(this.honpre.length > 0) { this.fullname += this.honpre + ' '; } From 8228a554a4d2cbdadb7187d026e1b5c25d2b404a Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Fri, 9 Mar 2012 10:29:00 +0100 Subject: [PATCH 047/132] Temporarily disabled multi_autoselect. --- apps/contacts/js/contacts.js | 14 +++++++------- apps/contacts/templates/part.contact.php | 8 ++++---- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/apps/contacts/js/contacts.js b/apps/contacts/js/contacts.js index 5f6129ca65..3ca6bc1ae9 100644 --- a/apps/contacts/js/contacts.js +++ b/apps/contacts/js/contacts.js @@ -252,12 +252,12 @@ Contacts={ $('#bday').datepicker({ dateFormat : 'dd-mm-yy' }); - /*$('#categories_value').find('select').multiselect({ + $('#categories_value').find('select').multiselect({ noneSelectedText: t('contacts', 'Select categories'), header: false, selectedList: 6, classes: 'categories' - });*/ + }); // Style phone types $('#phonelist').find('select.contacts_property').multiselect({ noneSelectedText: t('contacts', 'Select type'), @@ -299,7 +299,7 @@ Contacts={ click: function() { $(this).dialog('close'); } } ] ); - $('#categories').multiple_autocomplete({source: categories}); + //$('#categories').multiple_autocomplete({source: categories}); Contacts.UI.loadListHandlers(); }, Card:{ @@ -440,7 +440,7 @@ Contacts={ $('#rightcontent').data('id',this.id); console.log('loaded: ' + this.data.FN[0]['value']); this.populateNameFields(); - //this.loadCategories(); + this.loadCategories(); this.loadPhoto(); this.loadMails(); this.loadPhones(); @@ -458,7 +458,7 @@ Contacts={ } }, loadSingleProperties:function() { - var props = ['BDAY', 'NICKNAME', 'ORG', 'CATEGORIES']; + var props = ['BDAY', 'NICKNAME', 'ORG']; //, 'CATEGORIES']; // Clear all elements $('#ident .propertycontainer').each(function(){ if(props.indexOf($(this).data('element')) > -1) { @@ -494,12 +494,12 @@ Contacts={ $('#contact_identity').find('#org_label').show(); $('#contact_identity').find('#org_value').show(); break; - case 'CATEGORIES': + /*case 'CATEGORIES': $('#contact_identity').find('#categories').val(value); $('#contact_identity').find('#categories_value').data('checksum', checksum); $('#contact_identity').find('#categories_label').show(); $('#contact_identity').find('#categories_value').show(); - break; + break;*/ } } else { $('#contacts_propertymenu a[data-type="'+props[prop]+'"]').parent().show(); diff --git a/apps/contacts/templates/part.contact.php b/apps/contacts/templates/part.contact.php index 115458470b..67838238e2 100644 --- a/apps/contacts/templates/part.contact.php +++ b/apps/contacts/templates/part.contact.php @@ -55,15 +55,15 @@ $id = isset($_['id']) ? $_['id'] : ''; - - - + + -
      From 9e83f0247ff9c259a3dbf86106a6eeb06de42ba4 Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Tue, 13 Mar 2012 14:28:38 +0100 Subject: [PATCH 071/132] Added sync path for iOS/OS X. --- apps/contacts/templates/settings.php | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/apps/contacts/templates/settings.php b/apps/contacts/templates/settings.php index 8673e4521d..f56de0ec8b 100644 --- a/apps/contacts/templates/settings.php +++ b/apps/contacts/templates/settings.php @@ -1,7 +1,12 @@ -
      +
      t('Contacts'); ?>
      - t('CardDAV syncing address:'); ?> -
      + t('CardDAV syncing addresses:'); ?> +
      +
      t('Primary address (Kontact et al)'); ?>
      +
      /
      +
      t('iOS/OS X'); ?>
      +
      /principals//
      +
      From 4a91c6dbed149fd8828b6652c73db8e796c3c055 Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Tue, 13 Mar 2012 14:56:03 +0100 Subject: [PATCH 072/132] Make PHOTO deletable. --- apps/contacts/ajax/loadphoto.php | 11 ++++++++++- apps/contacts/js/contacts.js | 5 ++++- apps/contacts/templates/part.contact.php | 5 +++-- 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/apps/contacts/ajax/loadphoto.php b/apps/contacts/ajax/loadphoto.php index 1f4cde0b53..2c8bb7bf1e 100644 --- a/apps/contacts/ajax/loadphoto.php +++ b/apps/contacts/ajax/loadphoto.php @@ -43,8 +43,17 @@ if($id == '') { bailOut(OC_Contacts_App::$l10n->t('Missing contact id.')); } +$checksum = ''; +$vcard = OC_Contacts_App::getContactVCard( $id ); +foreach($vcard->children as $property){ + if($property->name == 'PHOTO') { + $checksum = md5($property->serialize()); + break; + } +} + $tmpl = new OC_TEMPLATE("contacts", "part.contactphoto"); $tmpl->assign('id', $id); $page = $tmpl->fetchPage(); -OC_JSON::success(array('data' => array('page'=>$page))); +OC_JSON::success(array('data' => array('page'=>$page, 'checksum'=>$checksum))); ?> diff --git a/apps/contacts/js/contacts.js b/apps/contacts/js/contacts.js index 13d71be384..18214cb1cc 100644 --- a/apps/contacts/js/contacts.js +++ b/apps/contacts/js/contacts.js @@ -662,7 +662,9 @@ Contacts={ } else if(type == 'single') { var proptype = Contacts.UI.propertyTypeFor(obj); console.log('deleteProperty, hiding: ' + proptype); - if(proptype == 'NOTE') { + var othertypes = ['NOTE', 'PHOTO']; + if(othertypes.indexOf(proptype) != -1) { + console.log('NOTE or PHOTO'); Contacts.UI.propertyContainerFor(obj).hide(); Contacts.UI.propertyContainerFor(obj).data('checksum', ''); } else { @@ -943,6 +945,7 @@ Contacts={ $.getJSON('ajax/loadphoto.php',{'id':this.id},function(jsondata){ if(jsondata.status == 'success'){ //alert(jsondata.data.page); + $('#file_upload_form').data('checksum', jsondata.data.checksum); $('#contacts_details_photo_wrapper').html(jsondata.data.page); } else{ diff --git a/apps/contacts/templates/part.contact.php b/apps/contacts/templates/part.contact.php index a3b4917ae9..cb1e080a40 100644 --- a/apps/contacts/templates/part.contact.php +++ b/apps/contacts/templates/part.contact.php @@ -23,8 +23,9 @@ $id = isset($_['id']) ? $_['id'] : '';
      - +
      +
      @@ -63,7 +64,7 @@ $id = isset($_['id']) ? $_['id'] : ''; - +
      -
      +
      From 122f7e4c2f4a95f904d052059e81ac855fbd2c3c Mon Sep 17 00:00:00 2001 From: Tom Needham Date: Sat, 17 Mar 2012 12:41:16 +0000 Subject: [PATCH 079/132] Dont truncate the time format --- apps/calendar/templates/settings.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/calendar/templates/settings.php b/apps/calendar/templates/settings.php index f74a45203e..fb2a04a649 100644 --- a/apps/calendar/templates/settings.php +++ b/apps/calendar/templates/settings.php @@ -31,7 +31,7 @@
      - " name="timeformat"> From 7ba8dbb92041d01ca70fca105897d3c374502343 Mon Sep 17 00:00:00 2001 From: Tom Needham Date: Sat, 17 Mar 2012 12:51:11 +0000 Subject: [PATCH 080/132] Don't truncate users email --- settings/css/settings.css | 1 + 1 file changed, 1 insertion(+) diff --git a/settings/css/settings.css b/settings/css/settings.css index e80de0f1ad..42576953d0 100644 --- a/settings/css/settings.css +++ b/settings/css/settings.css @@ -5,6 +5,7 @@ input#openid, input#webdav { width:20em; } #passworderror { display:none; } #passwordchanged { display:none; } input#identity { width:20em; } +#email { width: 17em; } .msg.success{ color:#fff; background-color:#0f0; padding:3px; text-shadow:1px 1px #000; } .msg.error{ color:#fff; background-color:#f00; padding:3px; text-shadow:1px 1px #000; } From de09883d860d6507a2d287d0b8bae394963c4b94 Mon Sep 17 00:00:00 2001 From: Bartek Przybylski Date: Sat, 17 Mar 2012 23:41:10 +0100 Subject: [PATCH 081/132] creating and retrive thumbnails for intermediate galleries --- apps/gallery/ajax/galleryOp.php | 2 ++ apps/gallery/lib/album.php | 16 ++++++++++++---- apps/gallery/lib/scanner.php | 9 +++++++++ 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/apps/gallery/ajax/galleryOp.php b/apps/gallery/ajax/galleryOp.php index 25976fa9e3..459c30f6ac 100644 --- a/apps/gallery/ajax/galleryOp.php +++ b/apps/gallery/ajax/galleryOp.php @@ -97,6 +97,8 @@ function handleGetGallery($path) { while ($r = $result->fetchRow()) { $album_name = $r['album_name']; $size=OC_Gallery_Album::getAlbumSize($r['album_id']); + // this is a fallback mechanism and seems expensive + if ($size == 0) $size = OC_Gallery_Album::getIntermediateGallerySize($r['album_path']); $a[] = array('name' => utf8_encode($album_name), 'numOfItems' => min($size, 10),'path'=>substr($r['album_path'], $pathLen)); } diff --git a/apps/gallery/lib/album.php b/apps/gallery/lib/album.php index e8698590e6..070afdd6cd 100644 --- a/apps/gallery/lib/album.php +++ b/apps/gallery/lib/album.php @@ -98,11 +98,19 @@ class OC_Gallery_Album { } public static function getAlbumSize($id){ - $sql = 'SELECT COUNT(*) as size FROM *PREFIX*gallery_photos WHERE album_id = ?'; - $stmt = OC_DB::prepare($sql); - $result=$stmt->execute(array($id))->fetchRow(); - return $result['size']; + $sql = 'SELECT COUNT(*) as size FROM *PREFIX*gallery_photos WHERE album_id = ?'; + $stmt = OC_DB::prepare($sql); + $result=$stmt->execute(array($id))->fetchRow(); + return $result['size']; } + + public static function getIntermediateGallerySize($path) { + $path .= '%'; + $sql = 'SELECT COUNT(*) as size FROM *PREFIX*gallery_photos photos, *PREFIX*gallery_albums albums WHERE photos.album_id = albums.album_id AND uid_owner = ? AND file_path LIKE ?'; + $stmt = OC_DB::prepare($sql); + $result = $stmt->execute(array(OC_User::getUser(), $path))->fetchRow(); + return $result['size']; + } } ?> diff --git a/apps/gallery/lib/scanner.php b/apps/gallery/lib/scanner.php index 929f8b7a2e..c8825c267e 100644 --- a/apps/gallery/lib/scanner.php +++ b/apps/gallery/lib/scanner.php @@ -95,6 +95,15 @@ class OC_Gallery_Scanner { foreach ($a as $e) { $p .= ($p == '/'?'':'/').$e; OC_Gallery_Album::create(OC_User::getUser(), $e, $p); + $arr = OC_FileCache::searchByMime('image','', OC_Filesystem::getRoot().$p); + $step = floor(count($arr)/10); + if ($step == 0) $step = 1; + $na = array(); + for ($j = 0; $j < count($arr); $j+=$step) { + $na[] = $p.$arr[$j]; + } + if (count($na)) + self::createThumbnails($e, $na); } } } From 03120959e9829eb1e33a2d1035b976438578fed3 Mon Sep 17 00:00:00 2001 From: Georg Ehrke Date: Mon, 19 Mar 2012 09:09:18 +0100 Subject: [PATCH 082/132] add a proper email address for lostpassword service - bugfix for oc-178 --- core/lostpassword/index.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/lostpassword/index.php b/core/lostpassword/index.php index 30caa2d23d..da0428e3ce 100644 --- a/core/lostpassword/index.php +++ b/core/lostpassword/index.php @@ -21,7 +21,8 @@ if (isset($_POST['user'])) { $tmpl->assign('link', $link); $msg = $tmpl->fetchPage(); $l = new OC_L10N('core'); - mail($email, $l->t('Owncloud password reset'), $msg); + $from = 'lostpassword-noreply@' . $_SERVER['HTTP_HOST']; + mail($email, $l->t('Owncloud password reset'), $msg, 'From:' . $from); } OC_Template::printGuestPage('core/lostpassword', 'lostpassword', array('error' => false, 'requested' => true)); } else { From 194211500b601d8582fa1e8396fb4c8e4970224d Mon Sep 17 00:00:00 2001 From: Georg Ehrke Date: Mon, 19 Mar 2012 09:58:44 +0100 Subject: [PATCH 083/132] register text/x-vcard as a fileaction for vcard import --- apps/contacts/js/loader.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/contacts/js/loader.js b/apps/contacts/js/loader.js index eb59185d72..95fd7dc94e 100644 --- a/apps/contacts/js/loader.js +++ b/apps/contacts/js/loader.js @@ -77,5 +77,7 @@ $(document).ready(function(){ if(typeof FileActions !== 'undefined'){ FileActions.register('text/vcard','importaddressbook', '', Contacts_Import.importdialog); FileActions.setDefault('text/vcard','importaddressbook'); + FileActions.register('text/x-vcard','importaddressbook', '', Contacts_Import.importdialog); + FileActions.setDefault('text/x-vcard','importaddressbook'); }; }); \ No newline at end of file From b13ab2b17eb485aec13c7fb1e88e25e1c9901d72 Mon Sep 17 00:00:00 2001 From: Arthur Schiwon Date: Mon, 19 Mar 2012 11:56:02 +0100 Subject: [PATCH 084/132] enable admin to turn off ZIP downloads user interface offers multi-file/folder downloads only if available make function name more clear --- files/admin.php | 3 +++ files/js/admin.js | 28 ++++++++++++++++++---------- files/js/fileactions.js | 15 +++++++++++---- files/templates/admin.php | 5 ++++- files/templates/index.php | 7 ++++++- lib/files.php | 21 ++++++++++++++++++--- 6 files changed, 60 insertions(+), 19 deletions(-) diff --git a/files/admin.php b/files/admin.php index 7e410652cf..b9c26c465f 100644 --- a/files/admin.php +++ b/files/admin.php @@ -37,10 +37,12 @@ if($_POST) { $maxZipInputSize=$_POST['maxZipInputSize']; OC_Preferences::setValue('', 'files', 'maxZipInputSize', OC_Helper::computerFileSize($maxZipInputSize)); } + OC_Preferences::setValue('', 'files', 'allowZipDownload', isset($_POST['allowZipDownload'])); }else{ $upload_max_filesize = OC_Helper::computerFileSize(ini_get('upload_max_filesize')); $post_max_size = OC_Helper::computerFileSize(ini_get('post_max_size')); $maxUploadFilesize = min($upload_max_filesize, $post_max_size); + $allowZipDownload = intval(OC_Preferences::getValue('', 'files', 'allowZipDownload', 1)); $maxZipInputSize = OC_Helper::humanfilesize(OC_Preferences::getValue('', 'files', 'maxZipInputSize', OC_Helper::computerFileSize('800 MB'))); } @@ -49,5 +51,6 @@ OC_App::setActiveNavigationEntry( "files_administration" ); $tmpl = new OC_Template( 'files', 'admin' ); $tmpl->assign( 'htaccessWorking', $htaccessWorking ); $tmpl->assign( 'uploadMaxFilesize', $maxUploadFilesize); +$tmpl->assign( 'allowZipDownload', $allowZipDownload); $tmpl->assign( 'maxZipInputSize', $maxZipInputSize); return $tmpl->fetchPage(); \ No newline at end of file diff --git a/files/js/admin.js b/files/js/admin.js index 5cbb2b9f5a..bfa9667063 100644 --- a/files/js/admin.js +++ b/files/js/admin.js @@ -1,15 +1,23 @@ -function switchPublicFolder() +function switchPublicFolder() { - var publicEnable = $('#publicEnable').is(':checked'); - var sharingaimGroup = $('input:radio[name=sharingaim]'); //find all radiobuttons of that group - $.each(sharingaimGroup, function(index, sharingaimItem) { - sharingaimItem.disabled = !publicEnable; //set all buttons to the correct state - }); + var publicEnable = $('#publicEnable').is(':checked'); + var sharingaimGroup = $('input:radio[name=sharingaim]'); //find all radiobuttons of that group + $.each(sharingaimGroup, function(index, sharingaimItem) { + sharingaimItem.disabled = !publicEnable; //set all buttons to the correct state + }); } $(document).ready(function(){ - switchPublicFolder(); // Execute the function after loading DOM tree - $('#publicEnable').click(function(){ - switchPublicFolder(); // To get rid of onClick() - }); + switchPublicFolder(); // Execute the function after loading DOM tree + $('#publicEnable').click(function(){ + switchPublicFolder(); // To get rid of onClick() + }); + + $('#allowZipDownload').bind('change', function() { + if($('#allowZipDownload').attr('checked')) { + $('#maxZipInputSize').removeAttr('disabled'); + } else { + $('#maxZipInputSize').attr('disabled', 'disabled'); + } + }); }); diff --git a/files/js/fileactions.js b/files/js/fileactions.js index b5dd398280..b33be280ad 100644 --- a/files/js/fileactions.js +++ b/files/js/fileactions.js @@ -106,7 +106,7 @@ FileActions={ element.hide(); parent.parent().children().last().append(element); } - $('#fileList .action').css('-o-transition-property','none');//temporarly disable + $('#fileList .action').css('-o-transition-property','none');//temporarly disable $('#fileList .action').fadeIn(200,function(){ $('#fileList .action').css('-o-transition-property','opacity'); }); @@ -128,8 +128,15 @@ FileActions={ } } -FileActions.register('all','Download',function(){return OC.imagePath('core','actions/download')},function(filename){ - window.location='ajax/download.php?files='+encodeURIComponent(filename)+'&dir='+encodeURIComponent($('#dir').val()); +$(document).ready(function(){ + if($('#allowZipDownload').val() == 1){ + var downloadScope = 'all'; + } else { + var downloadScope = 'file'; + } + FileActions.register(downloadScope,'Download',function(){return OC.imagePath('core','actions/download')},function(filename){ + window.location='ajax/download.php?files='+encodeURIComponent(filename)+'&dir='+encodeURIComponent($('#dir').val()); + }); }); FileActions.register('all','Delete',function(){return OC.imagePath('core','actions/delete')},function(filename){ @@ -144,4 +151,4 @@ FileActions.register('dir','Open','',function(filename){ window.location='index.php?dir='+encodeURIComponent($('#dir').val()).replace(/%2F/g, '/')+'/'+encodeURIComponent(filename); }); -FileActions.setDefault('dir','Open'); +FileActions.setDefault('dir','Open'); diff --git a/files/templates/admin.php b/files/templates/admin.php index 8c3ba56ad5..fd86d02e1e 100644 --- a/files/templates/admin.php +++ b/files/templates/admin.php @@ -6,7 +6,10 @@ '/>
      - '/>
      + />
      +
      + ' title="t( '0 is unlimited' ); ?>" />
      +
      diff --git a/files/templates/index.php b/files/templates/index.php index 7fc51c288e..497a0f36c0 100644 --- a/files/templates/index.php +++ b/files/templates/index.php @@ -40,7 +40,9 @@ t( 'Name' ); ?> - Download" /> + + Download" /> + @@ -66,3 +68,6 @@ t('Current scanning');?>

      + + + \ No newline at end of file diff --git a/lib/files.php b/lib/files.php index 50223df1d3..662f0b5972 100644 --- a/lib/files.php +++ b/lib/files.php @@ -59,7 +59,7 @@ class OC_Files { } if(is_array($files)){ - self::checkZipInputSize($dir,$files); + self::validateZipDownload($dir,$files); $executionTime = intval(ini_get('max_execution_time')); set_time_limit(0); $zip = new ZipArchive(); @@ -80,7 +80,7 @@ class OC_Files { $zip->close(); set_time_limit($executionTime); }elseif(OC_Filesystem::is_dir($dir.'/'.$files)){ - self::checkZipInputSize($dir,$files); + self::validateZipDownload($dir,$files); $executionTime = intval(ini_get('max_execution_time')); set_time_limit(0); $zip = new ZipArchive(); @@ -223,7 +223,22 @@ class OC_Files { * @param dir $dir * @param files $files */ - static function checkZipInputSize($dir, $files) { + static function validateZipDownload($dir, $files) { + if(!OC_Preferences::getValue('', 'files', 'allowZipDownload', 1)) { + $l = new OC_L10N('files'); + header("HTTP/1.0 409 Conflict"); + $tmpl = new OC_Template( '', 'error', 'user' ); + $errors = array( + array( + 'error' => $l->t('ZIP download is turned off.'), + 'hint' => $l->t('Files need to be downloaded one by one.') . '
      ' . $l->t('Back to Files') . '', + ) + ); + $tmpl->assign('errors', $errors); + $tmpl->printPage(); + exit; + } + $zipLimit = OC_Preferences::getValue('', 'files', 'maxZipInputSize', OC_Helper::computerFileSize('800 MB')); if($zipLimit > 0) { $totalsize = 0; From fa104fee17b36e619792599ab7fb921f95285833 Mon Sep 17 00:00:00 2001 From: Georg Ehrke Date: Mon, 19 Mar 2012 12:41:10 +0100 Subject: [PATCH 085/132] fix mimetype detection --- lib/helper.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/helper.php b/lib/helper.php index 0c6c73aa76..75942f092c 100644 --- a/lib/helper.php +++ b/lib/helper.php @@ -284,9 +284,7 @@ class OC_Helper { $isWrapped=(strpos($path,'://')!==false) and (substr($path,0,7)=='file://'); $mimeType='application/octet-stream'; if ($mimeType=='application/octet-stream') { - if(count(self::$mimetypes)>0){ - self::$mimetypes = include('mimetypes.fixlist.php'); - } + self::$mimetypes = include('mimetypes.fixlist.php'); $extention=strtolower(strrchr(basename($path), ".")); $extention=substr($extention,1);//remove leading . $mimeType=(isset(self::$mimetypes[$extention]))?self::$mimetypes[$extention]:'application/octet-stream'; From 3d8a09b14798724ba447d690f1f5502307da9f43 Mon Sep 17 00:00:00 2001 From: Bart Visscher Date: Mon, 19 Mar 2012 21:42:59 +0100 Subject: [PATCH 086/132] Split the init function in lib/base.php a bit --- lib/base.php | 85 ++++++++++++++++++++++++++++++---------------------- 1 file changed, 49 insertions(+), 36 deletions(-) diff --git a/lib/base.php b/lib/base.php index 9995544f14..54cc9f2c73 100644 --- a/lib/base.php +++ b/lib/base.php @@ -114,42 +114,7 @@ class OC{ return($mode); } - public static function init(){ - // register autoloader - spl_autoload_register(array('OC','autoload')); - - // set some stuff - //ob_start(); - error_reporting(E_ALL | E_STRICT); - if (defined('DEBUG') && DEBUG){ - ini_set('display_errors', 1); - } - - date_default_timezone_set('Europe/Berlin'); - ini_set('arg_separator.output','&'); - - //set http auth headers for apache+php-cgi work around - if (isset($_SERVER['HTTP_AUTHORIZATION']) && preg_match('/Basic\s+(.*)$/i', $_SERVER['HTTP_AUTHORIZATION'], $matches)) - { - list($name, $password) = explode(':', base64_decode($matches[1])); - $_SERVER['PHP_AUTH_USER'] = strip_tags($name); - $_SERVER['PHP_AUTH_PW'] = strip_tags($password); - } - - //set http auth headers for apache+php-cgi work around if variable gets renamed by apache - if (isset($_SERVER['REDIRECT_HTTP_AUTHORIZATION']) && preg_match('/Basic\s+(.*)$/i', $_SERVER['REDIRECT_HTTP_AUTHORIZATION'], $matches)) - { - list($name, $password) = explode(':', base64_decode($matches[1])); - $_SERVER['PHP_AUTH_USER'] = strip_tags($name); - $_SERVER['PHP_AUTH_PW'] = strip_tags($password); - } - - // register the stream wrappers - require_once('streamwrappers.php'); - stream_wrapper_register("fakedir", "OC_FakeDirStream"); - stream_wrapper_register('static', 'OC_StaticStreamWrapper'); - stream_wrapper_register('close', 'OC_CloseStreamWrapper'); - + public static function initPaths(){ // calculate the documentroot OC::$DOCUMENTROOT=realpath($_SERVER['DOCUMENT_ROOT']); OC::$SERVERROOT=str_replace("\\",'/',substr(__FILE__,0,-13)); @@ -211,14 +176,18 @@ class OC{ get_include_path().PATH_SEPARATOR. OC::$SERVERROOT ); + } + public static function checkInstalled() { // Redirect to installer if not installed if (!OC_Config::getValue('installed', false) && OC::$SUBURI != '/index.php') { $url = 'http://'.$_SERVER['SERVER_NAME'].OC::$WEBROOT.'/index.php'; header("Location: $url"); exit(); } + } + public static function checkSSL() { // redirect to https site if configured if( OC_Config::getValue( "forcessl", false )){ ini_set("session.cookie_secure", "on"); @@ -228,7 +197,9 @@ class OC{ exit(); } } + } + public static function checkUpgrade() { if(OC_Config::getValue('installed', false)){ $installedVersion=OC_Config::getValue('version','0.0.0'); $currentVersion=implode('.',OC_Util::getVersion()); @@ -250,6 +221,48 @@ class OC{ OC_App::updateApps(); } + } + + public static function init(){ + // register autoloader + spl_autoload_register(array('OC','autoload')); + + // set some stuff + //ob_start(); + error_reporting(E_ALL | E_STRICT); + if (defined('DEBUG') && DEBUG){ + ini_set('display_errors', 1); + } + + date_default_timezone_set('Europe/Berlin'); + ini_set('arg_separator.output','&'); + + //set http auth headers for apache+php-cgi work around + if (isset($_SERVER['HTTP_AUTHORIZATION']) && preg_match('/Basic\s+(.*)$/i', $_SERVER['HTTP_AUTHORIZATION'], $matches)) + { + list($name, $password) = explode(':', base64_decode($matches[1])); + $_SERVER['PHP_AUTH_USER'] = strip_tags($name); + $_SERVER['PHP_AUTH_PW'] = strip_tags($password); + } + + //set http auth headers for apache+php-cgi work around if variable gets renamed by apache + if (isset($_SERVER['REDIRECT_HTTP_AUTHORIZATION']) && preg_match('/Basic\s+(.*)$/i', $_SERVER['REDIRECT_HTTP_AUTHORIZATION'], $matches)) + { + list($name, $password) = explode(':', base64_decode($matches[1])); + $_SERVER['PHP_AUTH_USER'] = strip_tags($name); + $_SERVER['PHP_AUTH_PW'] = strip_tags($password); + } + + // register the stream wrappers + require_once('streamwrappers.php'); + stream_wrapper_register("fakedir", "OC_FakeDirStream"); + stream_wrapper_register('static', 'OC_StaticStreamWrapper'); + stream_wrapper_register('close', 'OC_CloseStreamWrapper'); + + self::initPaths(); + self::checkInstalled(); + self::checkSSL(); + self::checkUpgrade(); ini_set('session.cookie_httponly','1;'); session_start(); From 632b3cbbbb7e2d70599d20a517b1b0a05aece294 Mon Sep 17 00:00:00 2001 From: Bart Visscher Date: Mon, 19 Mar 2012 21:55:27 +0100 Subject: [PATCH 087/132] Cleanup the template code for redundant code --- lib/template.php | 255 ++++++++++++++++++++++++----------------------- 1 file changed, 128 insertions(+), 127 deletions(-) diff --git a/lib/template.php b/lib/template.php index eea2925975..5bcf52b932 100644 --- a/lib/template.php +++ b/lib/template.php @@ -140,7 +140,7 @@ class OC_Template{ /** * @brief Constructor * @param $app app providing the template - * @param $file name of the tempalte file (without suffix) + * @param $file name of the template file (without suffix) * @param $renderas = ""; produce a full page * @returns OC_Template object * @@ -151,10 +151,20 @@ class OC_Template{ * "admin". */ public function __construct( $app, $name, $renderas = "" ){ - // Read the selected theme from the config file - $theme=OC_Config::getValue( "theme" ); + // Set the private data + $this->renderas = $renderas; + $this->application = $app; + $this->vars = array(); + $this->l10n = new OC_L10N($app); - // Read the detected formfactor and use the right file name. + $this->findTemplate($name); + } + + /** + * @brief Returns the formfactor extention for current formfactor + */ + protected function getFormFactorExtension() + { $formfactor=$_SESSION['formfactor']; if($formfactor=='default') { $fext=''; @@ -167,70 +177,79 @@ class OC_Template{ }else{ $fext=''; } + return $fext; + } + /** + * @brief find the template with the given name + * @param $name of the template file (without suffix) + * + * Will select the template file for the selected theme and formfactor. + * Checking all the possible locations. + */ + protected function findTemplate($name) + { + // Read the selected theme from the config file + $theme=OC_Config::getValue( "theme" ); + + // Read the detected formfactor and use the right file name. + $fext = $this->getFormFactorExtension(); + + $app = $this->application; // Check if it is a app template or not. if( $app != "" ){ // Check if the app is in the app folder or in the root if( file_exists( OC::$APPSROOT."/apps/$app/templates/" )){ // Check if the template is overwritten by the selected theme - if( file_exists( OC::$SERVERROOT."/themes/$theme/apps/$app/templates/"."$name$fext.php" )){ - $template = OC::$SERVERROOT."/themes/$theme/apps/$app/templates/"."$name$fext.php"; - $path = OC::$SERVERROOT."/themes/$theme/apps/$app/templates/"; - }elseif( file_exists( OC::$SERVERROOT."/themes/$theme/apps/$app/templates/"."$name.php" )){ - $template = OC::$SERVERROOT."/themes/$theme/apps/$app/templates/"."$name.php"; - $path = OC::$SERVERROOT."/themes/$theme/apps/$app/templates/"; - }elseif( OC::$APPSROOT."/apps/$app/templates/"."$name$fext.php" ){ - $template = OC::$APPSROOT."/apps/$app/templates/"."$name$fext.php"; - $path = OC::$APPSROOT."/apps/$app/templates/"; - }else{ - $template = OC::$APPSROOT."/apps/$app/templates/"."$name.php"; - $path = OC::$APPSROOT."/apps/$app/templates/"; + if ($this->checkPathForTemplate(OC::$SERVERROOT."/themes/$theme/apps/$app/templates/", $name, $fext)) { + }elseif ($this->checkPathForTemplate(OC::$APPSROOT."/apps/$app/templates/", $name, $fext)) { } }else{ // Check if the template is overwritten by the selected theme - if( file_exists( OC::$SERVERROOT."/themes/$theme/$app/templates/"."$name$fext.php" )){ - $template = OC::$SERVERROOT."/themes/$theme/$app/templates/"."$name$fext.php"; - $path = OC::$SERVERROOT."/themes/$theme/$app/templates/"; - }elseif( file_exists( OC::$SERVERROOT."/themes/$theme/$app/templates/"."$name.php" )){ - $template = OC::$SERVERROOT."/themes/$theme/$app/templates/"."$name.php"; - $path = OC::$SERVERROOT."/themes/$theme/$app/templates/"; - }elseif( file_exists( OC::$SERVERROOT."/$app/templates/"."$name$fext.php" )){ - $template = OC::$SERVERROOT."/$app/templates/"."$name$fext.php"; - $path = OC::$SERVERROOT."/$app/templates/"; - }elseif( file_exists( OC::$SERVERROOT."/$app/templates/"."$name.php" )){ - $template = OC::$SERVERROOT."/$app/templates/"."$name.php"; - $path = OC::$SERVERROOT."/$app/templates/"; + if ($this->checkPathForTemplate(OC::$SERVERROOT."/themes/$theme/$app/templates/", $name, $fext)) { + }elseif ($this->checkPathForTemplate(OC::$SERVERROOT."/$app/templates/", $name, $fext)) { }else{ - echo('template not found: template:'.$name.' formfactor:'.$fext.' webroot:'.OC::$WEBROOT.' serverroot:'.OC::$SERVERROOT); + echo('template not found: template:'.$name.' formfactor:'.$fext.' webroot:'.OC::$WEBROOT.' serverroot:'.OC::$SERVERROOT); die(); } - } + } }else{ // Check if the template is overwritten by the selected theme - if( file_exists( OC::$SERVERROOT."/themes/$theme/core/templates/"."$name$fext.php" )){ - $template = OC::$SERVERROOT."/themes/$theme/core/templates/"."$name$fext.php"; - $path = OC::$SERVERROOT."/themes/$theme/core/templates/"; - }elseif( file_exists( OC::$SERVERROOT."/themes/$theme/core/templates/"."$name.php" )){ - $template = OC::$SERVERROOT."/themes/$theme/core/templates/"."$name.php"; - $path = OC::$SERVERROOT."/themes/$theme/core/templates/"; - }elseif( file_exists( OC::$SERVERROOT."/core/templates/"."$name$fext.php" )){ - $template = OC::$SERVERROOT."/core/templates/"."$name$fext.php"; - $path = OC::$SERVERROOT."/core/templates/"; + if ($this->checkPathForTemplate(OC::$SERVERROOT."/themes/$theme/core/templates/", $name, $fext)) { + } elseif ($this->checkPathForTemplate(OC::$SERVERROOT."/core/templates/", $name, $fext)) { }else{ - $template = OC::$SERVERROOT."/core/templates/"."$name.php"; - $path = OC::$SERVERROOT."/core/templates/"; + echo('template not found: template:'.$name.' formfactor:'.$fext.' webroot:'.OC::$WEBROOT.' serverroot:'.OC::$SERVERROOT); + die(); } } + } - - // Set the private data - $this->renderas = $renderas; - $this->application = $app; - $this->template = $template; - $this->path = $path; - $this->vars = array(); - $this->l10n = new OC_L10N($app); + /** + * @brief check Path For Template with and without $fext + * @param $path to check + * @param $name of the template file (without suffix) + * @param $fext formfactor extension + * @return bool true when found + * + * Will set $this->template and $this->path if there is a template at + * the specifief $path + */ + protected function checkPathForTemplate($path, $name, $fext) + { + if ($name =='') return false; + $template = null; + if( is_file( $path.$name.$fext.'.php' )){ + $template = $path.$name.$fext.'.php'; + }elseif( is_file( $path.$name.'.php' )){ + $template = $path.$name.'.php'; + } + if ($template) { + $this->template = $template; + $this->path = $path; + return true; + } + return false; } /** @@ -267,7 +286,7 @@ class OC_Template{ $this->vars[$key] = array( $value ); } } - + /** * @brief Add a custom element to the header * @param string tag tag name of the element @@ -295,11 +314,25 @@ class OC_Template{ } } + /* + * @brief append the $file-url if exist at $root + * @param $type of collection to use when appending + * @param $root path to check + * @param $web base for path + * @param $file the filename + */ + public function appendIfExist($type, $root, $web, $file) { + if (is_file($root.'/'.$file)) { + $this->append( $type, $web.'/'.$file); + return true; + } + return false; + } /** * @brief Proceeds the template * @returns content * - * This function proceeds the template. If $this->renderas is set, it will + * This function proceeds the template. If $this->renderas is set, it * will produce a full page. */ public function fetchPage(){ @@ -329,68 +362,44 @@ class OC_Template{ }else{ $page = new OC_Template( "core", "layout.guest" ); } - + // Read the selected theme from the config file $theme=OC_Config::getValue( "theme" ); // Read the detected formfactor and use the right file name. - $formfactor=$_SESSION['formfactor']; - if($formfactor=='default') { - $fext=''; - }elseif($formfactor=='mobile') { - $fext='.mobile'; - }elseif($formfactor=='tablet') { - $fext='.tablet'; - }elseif($formfactor=='standalone') { - $fext='.standalone'; - }else{ - $fext=''; - } + $fext = $this->getFormFactorExtension(); // Add the core js files or the js files provided by the selected theme foreach(OC_Util::$scripts as $script){ // Is it in 3rd party? - if(is_file(OC::$THIRDPARTYROOT."/$script.js" )){ - $page->append( "jsfiles", OC::$THIRDPARTYWEBROOT."/$script.js" ); + if($page->appendIfExist('jsfiles', OC::$THIRDPARTYROOT, OC::$THIRDPARTYWEBROOT, $script.'.js')) { // Is it in apps and overwritten by the theme? - }elseif(is_file(OC::$SERVERROOT."/themes/$theme/apps/$script$fext.js" )){ - $page->append( "jsfiles", OC::$WEBROOT."/themes/$theme/apps/$script$fext.js" ); - }elseif(is_file(OC::$SERVERROOT."/themes/$theme/apps/$script.js" )){ - $page->append( "jsfiles", OC::$WEBROOT."/themes/$theme/apps/$script.js" ); + }elseif($page->appendIfExist('jsfiles', OC::$SERVERROOT, OC::$WEBROOT, "themes/$theme/apps/$script$fext.js" )) { + }elseif($page->appendIfExist('jsfiles', OC::$SERVERROOT, OC::$WEBROOT, "themes/$theme/apps/$script.js" )) { // Is it part of an app? - }elseif(is_file(OC::$APPSROOT."/apps/$script$fext.js" )){ - $page->append( "jsfiles", OC::$APPSWEBROOT."/apps/$script$fext.js" ); - }elseif(is_file(OC::$APPSROOT."/apps/$script.js" )){ - $page->append( "jsfiles", OC::$APPSWEBROOT."/apps/$script.js" ); + }elseif($page->appendIfExist('jsfiles', OC::$APPSROOT, OC::$APPSWEBROOT, "apps/$script$fext.js" )) { + }elseif($page->appendIfExist('jsfiles', OC::$APPSROOT, OC::$APPSWEBROOT, "apps/$script.js" )) { // Is it in the owncloud root but overwritten by the theme? - }elseif(is_file(OC::$SERVERROOT."/themes/$theme/$script$fext.js" )){ - $page->append( "jsfiles", OC::$WEBROOT."/themes/$theme/$script$fext.js" ); - }elseif(is_file(OC::$SERVERROOT."/themes/$theme/$script.js" )){ - $page->append( "jsfiles", OC::$WEBROOT."/themes/$theme/$script.js" ); - + }elseif($page->appendIfExist('jsfiles', OC::$SERVERROOT, OC::$WEBROOT, "themes/$theme/$script$fext.js" )) { + }elseif($page->appendIfExist('jsfiles', OC::$SERVERROOT, OC::$WEBROOT, "themes/$theme/$script.js" )) { + // Is it in the owncloud root ? - }elseif(is_file(OC::$SERVERROOT."/$script$fext.js" )){ - $page->append( "jsfiles", OC::$WEBROOT."/$script$fext.js" ); - }elseif(is_file(OC::$SERVERROOT."/$script.js" )){ - $page->append( "jsfiles", OC::$WEBROOT."/$script.js" ); + }elseif($page->appendIfExist('jsfiles', OC::$SERVERROOT, OC::$WEBROOT, "$script$fext.js" )) { + }elseif($page->appendIfExist('jsfiles', OC::$SERVERROOT, OC::$WEBROOT, "$script.js" )) { // Is in core but overwritten by a theme? - }elseif(is_file(OC::$SERVERROOT."/themes/$theme/core/$script$fext.js" )){ - $page->append( "jsfiles", OC::$WEBROOT."/themes/$theme/core/$script$fext.js" ); - }elseif(is_file(OC::$SERVERROOT."/themes/$theme/core/$script.js" )){ - $page->append( "jsfiles", OC::$WEBROOT."/themes/$theme/core/$script.js" ); + }elseif($page->appendIfExist('jsfiles', OC::$SERVERROOT, OC::$WEBROOT, "themes/$theme/core/$script$fext.js" )) { + }elseif($page->appendIfExist('jsfiles', OC::$SERVERROOT, OC::$WEBROOT, "themes/$theme/core/$script.js" )) { // Is it in core? - }elseif(is_file(OC::$SERVERROOT."/core/$script$fext.js" )){ - $page->append( "jsfiles", OC::$WEBROOT."/core/$script$fext.js" ); - }elseif(is_file(OC::$SERVERROOT."/core/$script.js" )){ - $page->append( "jsfiles", OC::$WEBROOT."/core/$script.js" ); + }elseif($page->appendIfExist('jsfiles', OC::$SERVERROOT, OC::$WEBROOT, "core/$script$fext.js" )) { + }elseif($page->appendIfExist('jsfiles', OC::$SERVERROOT, OC::$WEBROOT, "core/$script.js" )) { }else{ - echo('js file not found: script:'.$script.' formfactor:'.$fext.' webroot:'.OC::$WEBROOT.' serverroot:'.OC::$SERVERROOT); + echo('js file not found: script:'.$script.' formfactor:'.$fext.' webroot:'.OC::$WEBROOT.' serverroot:'.OC::$SERVERROOT); die(); } @@ -398,54 +407,46 @@ class OC_Template{ // Add the css files foreach(OC_Util::$styles as $style){ // is it in 3rdparty? - if(is_file(OC::$THIRDPARTYROOT."/$style.css" )){ - $page->append( "cssfiles", OC::$THIRDPARTYWEBROOT."/$style.css" ); + if($page->appendIfExist('cssfiles', OC::$THIRDPARTYROOT, OC::$THIRDPARTYWEBROOT, $style.'.css')) { + // or in apps? - }elseif(is_file(OC::$APPSROOT."/apps/$style$fext.css" )){ - $page->append( "cssfiles", OC::$APPSWEBROOT."/apps/$style$fext.css" ); - }elseif(is_file(OC::$APPSROOT."/apps/$style.css" )){ - $page->append( "cssfiles", OC::$APPSWEBROOT."/apps/$style.css" ); + }elseif($page->appendIfExist('cssfiles', OC::$APPSROOT, OC::$APPSWEBROOT, "apps/$style$fext.css" )) { + }elseif($page->appendIfExist('cssfiles', OC::$APPSROOT, OC::$APPSWEBROOT, "apps/$style.css" )) { + // or in the owncloud root? - }elseif(is_file(OC::$SERVERROOT."/$style$fext.css" )){ - $page->append( "cssfiles", OC::$WEBROOT."/$style$fext.css" ); - }elseif(is_file(OC::$SERVERROOT."/$style.css" )){ - $page->append( "cssfiles", OC::$WEBROOT."/$style.css" ); - // or in core ? - }elseif(is_file(OC::$SERVERROOT."/core/$style$fext.css" )){ - $page->append( "cssfiles", OC::$WEBROOT."/core/$style$fext.css" ); - }elseif(is_file(OC::$SERVERROOT."/core/$style.css" )){ - $page->append( "cssfiles", OC::$WEBROOT."/core/$style.css" ); + }elseif($page->appendIfExist('cssfiles', OC::$SERVERROOT, OC::$WEBROOT, "$style$fext.css" )) { + }elseif($page->appendIfExist('cssfiles', OC::$SERVERROOT, OC::$WEBROOT, "$style.css" )) { + + // or in core ? + }elseif($page->appendIfExist('cssfiles', OC::$SERVERROOT, OC::$WEBROOT, "core/$style$fext.css" )) { + }elseif($page->appendIfExist('cssfiles', OC::$SERVERROOT, OC::$WEBROOT, "core/$style.css" )) { }else{ - echo('css file not found: style:'.$script.' formfactor:'.$fext.' webroot:'.OC::$WEBROOT.' serverroot:'.OC::$SERVERROOT); + echo('css file not found: style:'.$script.' formfactor:'.$fext.' webroot:'.OC::$WEBROOT.' serverroot:'.OC::$SERVERROOT); die(); } } - // Add the theme css files. you can override the default values here + // Add the theme css files. you can override the default values here if(!empty($theme)) { - foreach(OC_Util::$styles as $style){ - if(is_file(OC::$SERVERROOT."/themes/$theme/apps/$style$fext.css" )){ - $page->append( "cssfiles", OC::$WEBROOT."/themes/$theme/apps/$style$fext.css" ); - }elseif(is_file(OC::$SERVERROOT."/themes/$theme/apps/$style.css" )){ - $page->append( "cssfiles", OC::$WEBROOT."/themes/$theme/apps/$style.css" ); - }elseif(is_file(OC::$SERVERROOT."/themes/$theme/$style$fext.css" )){ - $page->append( "cssfiles", OC::$WEBROOT."/themes/$theme/$style$fext.css" ); - }elseif(is_file(OC::$SERVERROOT."/themes/$theme/$style.css" )){ - $page->append( "cssfiles", OC::$WEBROOT."/themes/$theme/$style.css" ); - }elseif(is_file(OC::$SERVERROOT."/themes/$theme/core/$style$fext.css" )){ - $page->append( "cssfiles", OC::$WEBROOT."/themes/$theme/core/$style$fext.css" ); - }elseif(is_file(OC::$SERVERROOT."/themes/$theme/core/$style.css" )){ - $page->append( "cssfiles", OC::$WEBROOT."/themes/$theme/core/$style.css" ); - } - } - } - + foreach(OC_Util::$styles as $style){ + if($page->appendIfExist('cssfiles', OC::$SERVERROOT, OC::$WEBROOT, "themes/$theme/apps/$style$fext.css" )) { + }elseif($page->appendIfExist('cssfiles', OC::$SERVERROOT, OC::$WEBROOT, "themes/$theme/apps/$style.css" )) { + + }elseif($page->appendIfExist('cssfiles', OC::$SERVERROOT, OC::$WEBROOT, "themes/$theme/$style$fext.css" )) { + }elseif($page->appendIfExist('cssfiles', OC::$SERVERROOT, OC::$WEBROOT, "themes/$theme/$style.css" )) { + + }elseif($page->appendIfExist('cssfiles', OC::$SERVERROOT, OC::$WEBROOT, "themes/$theme/core/$style$fext.css" )) { + }elseif($page->appendIfExist('cssfiles', OC::$SERVERROOT, OC::$WEBROOT, "themes/$theme/core/$style.css" )) { + } + } + } + // Add custom headers $page->assign('headers',$this->headers); foreach(OC_Util::$headers as $header){ $page->append('headers',$header); } - + // Add css files and js files $page->assign( "content", $data ); return $page->fetchPage(); From 89c39b47bcbe3b5085e9a528a6dc0afcff161f37 Mon Sep 17 00:00:00 2001 From: Georg Ehrke Date: Tue, 20 Mar 2012 18:46:56 +0100 Subject: [PATCH 088/132] add microsoft office mimetypes to the fixlist - bugfix for oc-357 --- lib/mimetypes.fixlist.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/mimetypes.fixlist.php b/lib/mimetypes.fixlist.php index 1c6acbc443..51f12dbcc2 100644 --- a/lib/mimetypes.fixlist.php +++ b/lib/mimetypes.fixlist.php @@ -10,5 +10,11 @@ return array( 'pl'=>'text/x-script.perl', 'py'=>'text/x-script.phyton', 'vcf' => 'text/vcard', - 'vcard' => 'text/vcard' + 'vcard' => 'text/vcard', + 'doc'=>'application/msword', + 'docx'=>'application/msword', + 'xls'=>'application/msexcel', + 'xlsx'=>'application/msexcel', + 'ppt'=>'application/mspowerpoint', + 'pptx'=>'application/mspowerpoint' ); From 19bbb61b20e1e9a7c7d4f9ef645ab65fcc453416 Mon Sep 17 00:00:00 2001 From: Georg Ehrke Date: Tue, 20 Mar 2012 19:48:08 +0100 Subject: [PATCH 089/132] fix spelling fail in texteditor's style.css --- apps/files_texteditor/css/style.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/files_texteditor/css/style.css b/apps/files_texteditor/css/style.css index e260ab0dd4..6a4392a08e 100644 --- a/apps/files_texteditor/css/style.css +++ b/apps/files_texteditor/css/style.css @@ -5,7 +5,7 @@ left: 12.5em; } #editorwrapper{ - position: absoloute; + position: absolute; height: 0; width: 0; top: 41px; From 7c815054c7bc43d1147294faddbb822c099a1f53 Mon Sep 17 00:00:00 2001 From: Arthur Schiwon Date: Wed, 21 Mar 2012 13:05:15 +0100 Subject: [PATCH 090/132] Config file is more appropriate here adjust default value --- files/admin.php | 8 ++++---- files/templates/index.php | 4 ++-- lib/files.php | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/files/admin.php b/files/admin.php index b9c26c465f..1fe1ff55a4 100644 --- a/files/admin.php +++ b/files/admin.php @@ -35,16 +35,16 @@ if($_POST) { } if(isset($_POST['maxZipInputSize'])) { $maxZipInputSize=$_POST['maxZipInputSize']; - OC_Preferences::setValue('', 'files', 'maxZipInputSize', OC_Helper::computerFileSize($maxZipInputSize)); + OC_Config::setValue('maxZipInputSize', OC_Helper::computerFileSize($maxZipInputSize)); } - OC_Preferences::setValue('', 'files', 'allowZipDownload', isset($_POST['allowZipDownload'])); + OC_Config::setValue('allowZipDownload', isset($_POST['allowZipDownload'])); }else{ $upload_max_filesize = OC_Helper::computerFileSize(ini_get('upload_max_filesize')); $post_max_size = OC_Helper::computerFileSize(ini_get('post_max_size')); $maxUploadFilesize = min($upload_max_filesize, $post_max_size); - $allowZipDownload = intval(OC_Preferences::getValue('', 'files', 'allowZipDownload', 1)); - $maxZipInputSize = OC_Helper::humanfilesize(OC_Preferences::getValue('', 'files', 'maxZipInputSize', OC_Helper::computerFileSize('800 MB'))); + $maxZipInputSize = OC_Helper::humanfilesize(OC_Config::getValue('maxZipInputSize', OC_Helper::computerFileSize('800 MB'))); } +$allowZipDownload = intval(OC_Config::getValue('allowZipDownload', true)); OC_App::setActiveNavigationEntry( "files_administration" ); diff --git a/files/templates/index.php b/files/templates/index.php index 497a0f36c0..3302cfa929 100644 --- a/files/templates/index.php +++ b/files/templates/index.php @@ -40,7 +40,7 @@ t( 'Name' ); ?> - + Download" /> @@ -70,4 +70,4 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/lib/files.php b/lib/files.php index 662f0b5972..57ebb9005a 100644 --- a/lib/files.php +++ b/lib/files.php @@ -224,7 +224,7 @@ class OC_Files { * @param files $files */ static function validateZipDownload($dir, $files) { - if(!OC_Preferences::getValue('', 'files', 'allowZipDownload', 1)) { + if(!OC_Config::getValue('allowZipDownload', true)) { $l = new OC_L10N('files'); header("HTTP/1.0 409 Conflict"); $tmpl = new OC_Template( '', 'error', 'user' ); @@ -239,7 +239,7 @@ class OC_Files { exit; } - $zipLimit = OC_Preferences::getValue('', 'files', 'maxZipInputSize', OC_Helper::computerFileSize('800 MB')); + $zipLimit = OC_Config::getValue('maxZipInputSize', OC_Helper::computerFileSize('800 MB')); if($zipLimit > 0) { $totalsize = 0; if(is_array($files)){ From d91bc9b317b440a0720fe9b7ca3f43538d840af8 Mon Sep 17 00:00:00 2001 From: Arthur Schiwon Date: Wed, 21 Mar 2012 13:10:02 +0100 Subject: [PATCH 091/132] use placeholder in template file --- files/index.php | 1 + files/templates/index.php | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/files/index.php b/files/index.php index 79261e495b..82d0960892 100644 --- a/files/index.php +++ b/files/index.php @@ -98,6 +98,7 @@ $tmpl->assign( 'readonly', !OC_Filesystem::is_writable($dir)); $tmpl->assign( "files", $files ); $tmpl->assign( 'uploadMaxFilesize', $maxUploadFilesize); $tmpl->assign( 'uploadMaxHumanFilesize', OC_Helper::humanFileSize($maxUploadFilesize)); +$tmpl->assign( 'allowZipDownload', intval(OC_Config::getValue('allowZipDownload', true))); $tmpl->printPage(); ?> diff --git a/files/templates/index.php b/files/templates/index.php index 3302cfa929..da1e58ce13 100644 --- a/files/templates/index.php +++ b/files/templates/index.php @@ -40,7 +40,7 @@ t( 'Name' ); ?> - + Download" /> @@ -70,4 +70,4 @@ - \ No newline at end of file + \ No newline at end of file From 5b03de9a66cf418ea2f269c9f061f44ca2146eb7 Mon Sep 17 00:00:00 2001 From: Georg Ehrke Date: Wed, 21 Mar 2012 11:57:15 +0100 Subject: [PATCH 092/132] fix comments in crypt lib --- apps/files_encryption/lib/crypt.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/files_encryption/lib/crypt.php b/apps/files_encryption/lib/crypt.php index 0a593b98c4..246d4f672d 100644 --- a/apps/files_encryption/lib/crypt.php +++ b/apps/files_encryption/lib/crypt.php @@ -26,7 +26,7 @@ // - Crypt/decrypt button in the userinterface // - Setting if crypto should be on by default // - Add a setting "Don´t encrypt files larger than xx because of performance reasons" -// - Transparent decrypt/encrpt in filesystem.php. Autodetect if a file is encrypted (.encrypted extensio) +// - Transparent decrypt/encrypt in filesystem.php. Autodetect if a file is encrypted (.encrypted extension) // - Don't use a password directly as encryption key. but a key which is stored on the server and encrypted with the user password. -> password change faster // - IMPORTANT! Check if the block lenght of the encrypted data stays the same From 0a93d4eccf405f7145694a21c4412ba213b50a4a Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Thu, 22 Mar 2012 19:54:24 +0100 Subject: [PATCH 093/132] loosen tests for mtime and ctime a bit --- tests/lib/filestorage.php | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/tests/lib/filestorage.php b/tests/lib/filestorage.php index 9ffa0eca9c..4858234a2d 100644 --- a/tests/lib/filestorage.php +++ b/tests/lib/filestorage.php @@ -135,10 +135,12 @@ abstract class Test_FileStorage extends UnitTestCase { $ctimeEnd=time(); $cTime=$this->instance->filectime('/lorem.txt'); $mTime=$this->instance->filemtime('/lorem.txt'); - $this->assertTrue($ctimeStart<=$cTime); - $this->assertTrue($cTime<=$ctimeEnd); - $this->assertTrue($ctimeStart<=$mTime); - $this->assertTrue($mTime<=$ctimeEnd); + if($cTime!=-1){//not everything can support ctime + $this->assertTrue(($ctimeStart-1)<=$cTime); + $this->assertTrue($cTime<=($ctimeEnd+1)); + } + $this->assertTrue(($ctimeStart-1)<=$mTime); + $this->assertTrue($mTime<=($ctimeEnd+1)); $this->assertEqual(filesize($textFile),$this->instance->filesize('/lorem.txt')); $stat=$this->instance->stat('/lorem.txt'); @@ -153,8 +155,8 @@ abstract class Test_FileStorage extends UnitTestCase { $originalCTime=$cTime; $cTime=$this->instance->filectime('/lorem.txt'); $mTime=$this->instance->filemtime('/lorem.txt'); - $this->assertTrue($mtimeStart<=$mTime); - $this->assertTrue($mTime<=$mtimeEnd); + $this->assertTrue(($mtimeStart-1)<=$mTime); + $this->assertTrue($mTime<=($mtimeEnd+1)); $this->assertEqual($cTime,$originalCTime); if($this->instance->touch('/lorem.txt',100)!==false){ @@ -170,8 +172,8 @@ abstract class Test_FileStorage extends UnitTestCase { $mtimeEnd=time(); $originalCTime=$cTime; $mTime=$this->instance->filemtime('/lorem.txt'); - $this->assertTrue($mtimeStart<=$mTime); - $this->assertTrue($mTime<=$mtimeEnd); + $this->assertTrue(($mtimeStart-1)<=$mTime); + $this->assertTrue($mTime<=($mtimeEnd+1)); } public function testSearch(){ From 82b54938e32a980d3d268a63fdf56598f12e2ff4 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Thu, 22 Mar 2012 19:56:19 +0100 Subject: [PATCH 094/132] ftp storage backend --- apps/files_remote/appinfo/app.php | 9 ++ apps/files_remote/appinfo/info.xml | 10 ++ apps/files_remote/lib/ftp.php | 157 +++++++++++++++++++++++++++++ apps/files_remote/tests/config.php | 9 ++ apps/files_remote/tests/ftp.php | 28 +++++ 5 files changed, 213 insertions(+) create mode 100644 apps/files_remote/appinfo/app.php create mode 100644 apps/files_remote/appinfo/info.xml create mode 100644 apps/files_remote/lib/ftp.php create mode 100644 apps/files_remote/tests/config.php create mode 100644 apps/files_remote/tests/ftp.php diff --git a/apps/files_remote/appinfo/app.php b/apps/files_remote/appinfo/app.php new file mode 100644 index 0000000000..f94e813ea5 --- /dev/null +++ b/apps/files_remote/appinfo/app.php @@ -0,0 +1,9 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +OC::$CLASSPATH['OC_Filestorage_FTP']='apps/files_remote/lib/ftp.php'; diff --git a/apps/files_remote/appinfo/info.xml b/apps/files_remote/appinfo/info.xml new file mode 100644 index 0000000000..0720b6095b --- /dev/null +++ b/apps/files_remote/appinfo/info.xml @@ -0,0 +1,10 @@ + + + files_remote + Remote storage support + Mount remote storage sources + 0.1 + AGPL + Robin Appelman + 3 + diff --git a/apps/files_remote/lib/ftp.php b/apps/files_remote/lib/ftp.php new file mode 100644 index 0000000000..802446b4fd --- /dev/null +++ b/apps/files_remote/lib/ftp.php @@ -0,0 +1,157 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +class OC_FileStorage_FTP extends OC_Filestorage_Common{ + private $password; + private $user; + private $host; + private $secure; + private $root; + + private static $tempFiles=array(); + + public function __construct($params){ + $this->host=$params['host']; + $this->user=$params['user']; + $this->password=$params['password']; + $this->secure=isset($params['secure'])?(bool)$params['secure']:false; + $this->root=isset($params['root'])?$params['root']:'/'; + if(substr($this->root,0,1)!='/'){ + $this->root='/'.$this->root; + } + + //create the root folder if necesary + mkdir($this->constructUrl('')); + } + + /** + * construct the ftp url + * @param string path + * @return string + */ + public function constructUrl($path){ + $url='ftp'; + if($this->secure){ + $url.='s'; + } + $url.='://'.$this->user.':'.$this->password.'@'.$this->host.$this->root.$path; + return $url; + } + + public function mkdir($path){ + return mkdir($this->constructUrl($path)); + } + + public function rmdir($path){ + if($this->file_exists($path)){ + $succes=rmdir($this->constructUrl($path)); + clearstatcache(); + return $succes; + }else{ + return false; + } + } + + public function opendir($path){ + return opendir($this->constructUrl($path)); + } + + public function filetype($path){ + return filetype($this->constructUrl($path)); + } + + public function is_readable($path){ + return true;//not properly supported + } + + public function is_writable($path){ + return true;//not properly supported + } + + public function file_exists($path){ + return file_exists($this->constructUrl($path)); + } + + public function unlink($path){ + $succes=unlink($this->constructUrl($path)); + clearstatcache(); + return $succes; + } + + public function fopen($path,$mode){ + switch($mode){ + case 'r': + case 'rb': + case 'w': + case 'wb': + case 'a': + case 'ab': + //these are supported by the wrapper + $context = stream_context_create(array('ftp' => array('overwrite' => true))); + return fopen($this->constructUrl($path),$mode,false,$context); + case 'r+': + case 'w+': + case 'wb+': + case 'a+': + case 'x': + case 'x+': + case 'c': + case 'c+': + //emulate these + if(strrpos($path,'.')!==false){ + $ext=substr($path,strrpos($path,'.')); + }else{ + $ext=''; + } + $tmpFile=OC_Helper::tmpFile($ext); + OC_CloseStreamWrapper::$callBacks[$tmpFile]=array($this,'writeBack'); + if($this->file_exists($path)){ + $this->getFile($path,$tmpFile); + } + self::$tempFiles[$tmpFile]=$path; + return fopen('close://'.$tmpFile,$mode); + } + } + + public function writeBack($tmpFile){ + if(isset(self::$tempFiles[$tmpFile])){ + $this->uploadFile($tmpFile,self::$tempFiles[$tmpFile]); + unlink($tmpFile); + } + } + + public function free_space($path){ + return 0; + } + + public function touch($path,$mtime=null){ + if(is_null($mtime)){ + $fh=$this->fopen($path,'a'); + fwrite($fh,''); + fclose($fh); + }else{ + return false;//not supported + } + } + + public function getFile($path,$target){ + return copy($this->constructUrl($path),$target); + } + + public function uploadFile($path,$target){ + return copy($path,$this->constructUrl($target)); + } + + public function rename($path1,$path2){ + return rename($this->constructUrl($path1),$this->constructUrl($path2)); + } + + public function stat($path){ + return stat($this->constructUrl($path)); + } +} diff --git a/apps/files_remote/tests/config.php b/apps/files_remote/tests/config.php new file mode 100644 index 0000000000..5410578291 --- /dev/null +++ b/apps/files_remote/tests/config.php @@ -0,0 +1,9 @@ +array( + 'host'=>'localhost', + 'user'=>'test', + 'password'=>'test', + 'root'=>'/test', + ) +); diff --git a/apps/files_remote/tests/ftp.php b/apps/files_remote/tests/ftp.php new file mode 100644 index 0000000000..2d5405ccda --- /dev/null +++ b/apps/files_remote/tests/ftp.php @@ -0,0 +1,28 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +class Test_Filestorage_FTP extends Test_FileStorage { + /** + * @var string tmpDir + */ + private $config; + private $id; + + public function setUp(){ + $id=uniqid(); + $this->config=include('apps/files_remote/tests/config.php'); + $this->config['ftp']['root'].='/'.$id;//make sure we have an new empty folder to work in + $this->instance=new OC_Filestorage_FTP($this->config['ftp']); + } + + public function tearDown(){ + OC_Helper::rmdirr($this->instance->constructUrl('')); + } +} + +?> \ No newline at end of file From a191b75c3192156c67f45778e05cf88fff42bf50 Mon Sep 17 00:00:00 2001 From: Frank Karlitschek Date: Fri, 23 Mar 2012 15:52:41 +0100 Subject: [PATCH 095/132] make it possible to connect to other ocs appstores and other ocs knowledgebase servers. also make it possible to switch the app store and the knowledgebase off completely. --- config/config.sample.php | 4 ++++ lib/app.php | 9 ++++--- lib/ocsclient.php | 52 ++++++++++++++++++++++++++++++++++++---- 3 files changed, 57 insertions(+), 8 deletions(-) mode change 100644 => 100755 lib/app.php mode change 100644 => 100755 lib/ocsclient.php diff --git a/config/config.sample.php b/config/config.sample.php index 5206737455..199c9248c5 100755 --- a/config/config.sample.php +++ b/config/config.sample.php @@ -15,6 +15,10 @@ $CONFIG = array( "theme" => "", "3rdpartyroot" => "", "3rdpartyurl" => "", +"knowledgebaseenabled" => true, +"knowledgebaseurl" => "", +"appstoreenabled" => true, +"appstoreurl" => "", // "datadirectory" => "" ); ?> diff --git a/lib/app.php b/lib/app.php old mode 100644 new mode 100755 index 64cbe8894e..3daf539aa2 --- a/lib/app.php +++ b/lib/app.php @@ -210,10 +210,13 @@ class OC_App{ public static function getSettingsNavigation(){ $l=new OC_L10N('core'); + $settings = array(); // by default, settings only contain the help menu - $settings = array( - array( "id" => "help", "order" => 1000, "href" => OC_Helper::linkTo( "settings", "help.php" ), "name" => $l->t("Help"), "icon" => OC_Helper::imagePath( "settings", "help.svg" )) - ); + if(OC_Config::getValue('knowledgebaseenabled', true)==true){ + $settings = array( + array( "id" => "help", "order" => 1000, "href" => OC_Helper::linkTo( "settings", "help.php" ), "name" => $l->t("Help"), "icon" => OC_Helper::imagePath( "settings", "help.svg" )) + ); + } // if the user is logged-in if (OC_User::isLoggedIn()) { diff --git a/lib/ocsclient.php b/lib/ocsclient.php old mode 100644 new mode 100755 index 9d5932fb72..d830a4f3e7 --- a/lib/ocsclient.php +++ b/lib/ocsclient.php @@ -28,6 +28,38 @@ class OC_OCSClient{ + /** + * @brief Get the url of the OCS AppStore server. + * @returns string of the AppStore server + * + * This function returns the url of the OCS AppStore server. It´s possible to set it in the config file or it will fallback to the default + */ + private static function getAppStoreURL(){ + $configurl=OC_Config::getValue('appstoreurl', ''); + if($configurl<>'') { + $url=$configurl; + }else{ + $url='http://api.apps.owncloud.com/v1'; + } + return($url); + } + + /** + * @brief Get the url of the OCS KB server. + * @returns string of the KB server + * This function returns the url of the OCS knowledge base server. It´s possible to set it in the config file or it will fallback to the default + */ + private static function getKBURL(){ + $configurl=OC_Config::getValue('knowledgebaseurl', ''); + if($configurl<>'') { + $url=$configurl; + }else{ + $url='http://api.apps.owncloud.com/v1'; + } + return($url); + } + + /** * @brief Get all the categories from the OCS server * @returns array with category ids @@ -35,7 +67,7 @@ class OC_OCSClient{ * This function returns a list of all the application categories on the OCS server */ public static function getCategories(){ - $url='http://api.apps.owncloud.com/v1/content/categories'; + $url=OC_OCSClient::getAppStoreURL().'/content/categories'; $xml=@file_get_contents($url); if($xml==FALSE){ @@ -64,12 +96,16 @@ class OC_OCSClient{ * This function returns a list of all the applications on the OCS server */ public static function getApplications($categories){ + if(OC_Config::getValue('appstoreenabled', true)==false){ + return(array()); + } + if(is_array($categories)) { $categoriesstring=implode('x',$categories); }else{ $categoriesstring=$categories; } - $url='http://api.apps.owncloud.com/v1/content/data?categories='.urlencode($categoriesstring).'&sortmode=new&page=0&pagesize=10'; + $url=OC_OCSClient::getAppStoreURL().'/content/data?categories='.urlencode($categoriesstring).'&sortmode=new&page=0&pagesize=10'; $apps=array(); $xml=@file_get_contents($url); if($xml==FALSE){ @@ -104,7 +140,7 @@ class OC_OCSClient{ * This function returns an applications from the OCS server */ public static function getApplication($id){ - $url='http://api.apps.owncloud.com/v1/content/data/'.urlencode($id); + $url=OC_OCSClient::getAppStoreURL().'/content/data/'.urlencode($id); $xml=@file_get_contents($url); if($xml==FALSE){ @@ -137,7 +173,7 @@ class OC_OCSClient{ * This function returns an download url for an applications from the OCS server */ public static function getApplicationDownload($id,$item){ - $url='http://api.apps.owncloud.com/v1/content/download/'.urlencode($id).'/'.urlencode($item); + $url=OC_OCSClient::getAppStoreURL().'/content/download/'.urlencode($id).'/'.urlencode($item); $xml=@file_get_contents($url); if($xml==FALSE){ @@ -164,9 +200,15 @@ class OC_OCSClient{ * This function returns a list of all the knowledgebase entries from the OCS server */ public static function getKnownledgebaseEntries($page,$pagesize){ + if(OC_Config::getValue('knowledgebaseenabled', true)==false){ + $kbe=array(); + $kbe['totalitems']=0; + return $kbe; + } + $p= (int) $page; $s= (int) $pagesize; - $url='http://api.apps.owncloud.com/v1/knowledgebase/data?type=150&page='.$p.'&pagesize='.$s; + $url=OC_OCSClient::getKBURL().'/knowledgebase/data?type=150&page='.$p.'&pagesize='.$s; $kbe=array(); $xml=@file_get_contents($url); From 7cad6ccce0f2fdcfc61e1071cb6373e9d28bcd63 Mon Sep 17 00:00:00 2001 From: Frank Karlitschek Date: Fri, 23 Mar 2012 16:48:16 +0100 Subject: [PATCH 096/132] =?UTF-8?q?don=C2=B4t=20show=20ugly=20error=20mess?= =?UTF-8?q?age?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/helper.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) mode change 100644 => 100755 lib/helper.php diff --git a/lib/helper.php b/lib/helper.php old mode 100644 new mode 100755 index 75942f092c..66f31d929b --- a/lib/helper.php +++ b/lib/helper.php @@ -220,7 +220,7 @@ class OC_Helper { $fullpath = $path.'/'.$file; if(is_link($fullpath)) return FALSE; - elseif(!is_dir($fullpath) && !chmod($fullpath, $filemode)) + elseif(!is_dir($fullpath) && !@chmod($fullpath, $filemode)) return FALSE; elseif(!self::chmodr($fullpath, $filemode)) return FALSE; From 45b320d674332dc224cf95c82e2e02e25ac66661 Mon Sep 17 00:00:00 2001 From: Georg Ehrke Date: Fri, 23 Mar 2012 16:53:44 +0100 Subject: [PATCH 097/132] use unnamed as title for a bookmark if no title was entered and curl fails --- apps/bookmarks/bookmarksHelper.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/apps/bookmarks/bookmarksHelper.php b/apps/bookmarks/bookmarksHelper.php index 8def7401e2..7ada69014f 100644 --- a/apps/bookmarks/bookmarksHelper.php +++ b/apps/bookmarks/bookmarksHelper.php @@ -71,7 +71,7 @@ function getURLMetadata($url) { return $metadata; } -function addBookmark($url, $title='', $tags='') { +function addBookmark($url, $title, $tags='') { $CONFIG_DBTYPE = OC_Config::getValue( "dbtype", "sqlite" ); if( $CONFIG_DBTYPE == 'sqlite' or $CONFIG_DBTYPE == 'sqlite3' ){ $_ut = "strftime('%s','now')"; @@ -93,6 +93,11 @@ function addBookmark($url, $title='', $tags='') { $title = $metadata['title']; } + if(empty($title)) { + $l = new OC_L10N('bookmarks'); + $title = $l->t('unnamed'); + } + $params=array( htmlspecialchars_decode($url), htmlspecialchars_decode($title), From b63b377c4d173b3a62b93360909857a1d6a62837 Mon Sep 17 00:00:00 2001 From: Georg Ehrke Date: Fri, 23 Mar 2012 16:58:48 +0100 Subject: [PATCH 098/132] Bookmarks: make link text click clickable too - bugfix for oc-131 --- apps/bookmarks/js/bookmarks.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/bookmarks/js/bookmarks.js b/apps/bookmarks/js/bookmarks.js index fa5adde254..3557810d4b 100644 --- a/apps/bookmarks/js/bookmarks.js +++ b/apps/bookmarks/js/bookmarks.js @@ -145,7 +145,7 @@ function updateBookmarksList(bookmark) { '

      '+ '' + encodeEntities(bookmark.title) + '' + '

      ' + - '

      ' + encodeEntities(bookmark.url) + '

      ' + + '

      ' + encodeEntities(bookmark.url) + '

      ' + '' ); if(taglist != '') { From ac8362e34a89b0e513e1304cf0f111c52d27f9e5 Mon Sep 17 00:00:00 2001 From: Georg Ehrke Date: Fri, 23 Mar 2012 17:09:51 +0100 Subject: [PATCH 099/132] check if the title of an event is null - bugfix for oc-139 --- apps/calendar/ajax/events.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/calendar/ajax/events.php b/apps/calendar/ajax/events.php index 922df90b76..cf768f51c6 100755 --- a/apps/calendar/ajax/events.php +++ b/apps/calendar/ajax/events.php @@ -12,7 +12,7 @@ require_once('when/When.php'); function create_return_event($event, $vevent){ $return_event = array(); $return_event['id'] = (int)$event['id']; - $return_event['title'] = htmlspecialchars($event['summary']); + $return_event['title'] = htmlspecialchars(($event['summary']!=NULL)?$event['summary']:$l->t('unnamed')); $return_event['description'] = isset($vevent->DESCRIPTION)?htmlspecialchars($vevent->DESCRIPTION->value):''; $last_modified = $vevent->__get('LAST-MODIFIED'); if ($last_modified){ From 0e11cc9f6ff6176ae723acd8facef9237252be5f Mon Sep 17 00:00:00 2001 From: Georg Ehrke Date: Fri, 23 Mar 2012 17:27:52 +0100 Subject: [PATCH 100/132] fix previous made bug and fix oc bug - oc-139 --- apps/calendar/ajax/events.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/calendar/ajax/events.php b/apps/calendar/ajax/events.php index cf768f51c6..c62f93c540 100755 --- a/apps/calendar/ajax/events.php +++ b/apps/calendar/ajax/events.php @@ -8,11 +8,13 @@ require_once ('../../../lib/base.php'); require_once('when/When.php'); - +$l = new OC_L10N('calendar'); +$unnamed = $l->t('unnamed'); function create_return_event($event, $vevent){ $return_event = array(); + global $unnamed; $return_event['id'] = (int)$event['id']; - $return_event['title'] = htmlspecialchars(($event['summary']!=NULL)?$event['summary']:$l->t('unnamed')); + $return_event['title'] = htmlspecialchars(($event['summary']!=NULL || $event['summary'] != '')?$event['summary']: $unnamed); $return_event['description'] = isset($vevent->DESCRIPTION)?htmlspecialchars($vevent->DESCRIPTION->value):''; $last_modified = $vevent->__get('LAST-MODIFIED'); if ($last_modified){ From 109d80661713b896287c0a58ddf1f55604ad1298 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Fri, 23 Mar 2012 18:52:41 +0100 Subject: [PATCH 101/132] make sure we can load OC_Config when we need it --- lib/base.php | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/base.php b/lib/base.php index 54cc9f2c73..b07ac5af41 100644 --- a/lib/base.php +++ b/lib/base.php @@ -139,6 +139,12 @@ class OC{ OC::$WEBROOT='/'.OC::$WEBROOT; } + // ensure we can find OC_Config + set_include_path( + OC::$SERVERROOT.'/lib'.PATH_SEPARATOR. + get_include_path() + ); + // search the 3rdparty folder if(OC_Config::getValue('3rdpartyroot', '')<>'' and OC_Config::getValue('3rdpartyurl', '')<>''){ OC::$THIRDPARTYROOT=OC_Config::getValue('3rdpartyroot', ''); @@ -227,6 +233,7 @@ class OC{ // register autoloader spl_autoload_register(array('OC','autoload')); + // set some stuff //ob_start(); error_reporting(E_ALL | E_STRICT); @@ -252,6 +259,8 @@ class OC{ $_SERVER['PHP_AUTH_USER'] = strip_tags($name); $_SERVER['PHP_AUTH_PW'] = strip_tags($password); } + + self::initPaths(); // register the stream wrappers require_once('streamwrappers.php'); @@ -259,7 +268,6 @@ class OC{ stream_wrapper_register('static', 'OC_StaticStreamWrapper'); stream_wrapper_register('close', 'OC_CloseStreamWrapper'); - self::initPaths(); self::checkInstalled(); self::checkSSL(); self::checkUpgrade(); From e0cbefc7275fa622f15dc1e57be67fd283f28056 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Fri, 23 Mar 2012 18:54:38 +0100 Subject: [PATCH 102/132] webdav storage backend --- apps/files_remote/appinfo/app.php | 1 + apps/files_remote/lib/webdav.php | 293 +++++++++++++++++++++++++++++ apps/files_remote/tests/config.php | 8 +- apps/files_remote/tests/ftp.php | 5 - apps/files_remote/tests/webdav.php | 23 +++ 5 files changed, 324 insertions(+), 6 deletions(-) create mode 100644 apps/files_remote/lib/webdav.php create mode 100644 apps/files_remote/tests/webdav.php diff --git a/apps/files_remote/appinfo/app.php b/apps/files_remote/appinfo/app.php index f94e813ea5..25473d87fe 100644 --- a/apps/files_remote/appinfo/app.php +++ b/apps/files_remote/appinfo/app.php @@ -7,3 +7,4 @@ */ OC::$CLASSPATH['OC_Filestorage_FTP']='apps/files_remote/lib/ftp.php'; +OC::$CLASSPATH['OC_Filestorage_DAV']='apps/files_remote/lib/webdav.php'; diff --git a/apps/files_remote/lib/webdav.php b/apps/files_remote/lib/webdav.php new file mode 100644 index 0000000000..7a2da5c8ec --- /dev/null +++ b/apps/files_remote/lib/webdav.php @@ -0,0 +1,293 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +class OC_FileStorage_DAV extends OC_Filestorage_Common{ + private $password; + private $user; + private $host; + private $secure; + private $root; + /** + * @var Sabre_DAV_Client + */ + private $client; + + private static $tempFiles=array(); + + public function __construct($params){ + $this->host=$params['host']; + $this->user=$params['user']; + $this->password=$params['password']; + $this->secure=isset($params['secure'])?(bool)$params['secure']:false; + $this->root=isset($params['root'])?$params['root']:'/'; + if(substr($this->root,0,1)!='/'){ + $this->root='/'.$this->root; + } + if(substr($this->root,-1,1)!='/'){ + $this->root.='/'; + } + + $settings = array( + 'baseUri' => $this->createBaseUri(), + 'userName' => $this->user, + 'password' => $this->password, + ); + $this->client = new Sabre_DAV_Client($settings); + + //create the root folder if necesary + $this->mkdir(''); + } + + private function createBaseUri(){ + $baseUri='http'; + if($this->secure){ + $baseUri.'s'; + } + $baseUri.='://'.$this->host.$this->root; + return $baseUri; + } + + public function mkdir($path){ + $path=$this->cleanPath($path); + return $this->simpleResponse('MKCOL',$path,null,201); + } + + public function rmdir($path){ + $path=$this->cleanPath($path); + return $this->simpleResponse('DELETE',$path,null,204); + } + + public function opendir($path){ + $path=$this->cleanPath($path); + try{ + $response=$this->client->propfind($path, array(),1); + $stripLength=strlen($this->root)+strlen($path); + $id=md5('webdav'.$this->root.$path); + OC_FakeDirStream::$dirs[$id]=array(); + foreach($response as $file=>$data){ + //strip root and path + $file=trim(substr($file,$stripLength)); + $file=trim($file,'/'); + if($file){ + OC_FakeDirStream::$dirs[$id][]=$file; + } + } + return opendir('fakedir://'.$id); + }catch(Exception $e){ + return false; + } + } + + public function filetype($path){ + $path=$this->cleanPath($path); + try{ + $response=$this->client->propfind($path, array('{DAV:}resourcetype')); + $responseType=$response["{DAV:}resourcetype"]->resourceType; + return (count($responseType)>0 and $responseType[0]=="{DAV:}collection")?'dir':'file'; + }catch(Exception $e){ + return false; + } + } + + public function is_readable($path){ + return true;//not properly supported + } + + public function is_writable($path){ + return true;//not properly supported + } + + public function file_exists($path){ + $path=$this->cleanPath($path); + try{ + $response=$this->client->propfind($path, array('{DAV:}resourcetype')); + return true;//no 404 exception + }catch(Exception $e){ + return false; + } + } + + public function unlink($path){ + return $this->simpleResponse('DELETE',$path,null,204); + } + + public function fopen($path,$mode){ + $path=$this->cleanPath($path); + switch($mode){ + case 'r': + case 'rb': + //straight up curl instead of sabredav here, sabredav put's the entire get result in memory + $curl = curl_init(); + $fp = fopen('php://temp', 'r+'); + curl_setopt($curl,CURLOPT_USERPWD,$this->user.':'.$this->password); + curl_setopt($curl, CURLOPT_URL, $this->createBaseUri().$path); + curl_setopt($curl, CURLOPT_FILE, $fp); + + curl_exec ($curl); + curl_close ($curl); + rewind($fp); + return $fp; + case 'w': + case 'wb': + case 'a': + case 'ab': + case 'r+': + case 'w+': + case 'wb+': + case 'a+': + case 'x': + case 'x+': + case 'c': + case 'c+': + //emulate these + if(strrpos($path,'.')!==false){ + $ext=substr($path,strrpos($path,'.')); + }else{ + $ext=''; + } + $tmpFile=OC_Helper::tmpFile($ext); + OC_CloseStreamWrapper::$callBacks[$tmpFile]=array($this,'writeBack'); + if($this->file_exists($path)){ + $this->getFile($path,$tmpFile); + } + self::$tempFiles[$tmpFile]=$path; + return fopen('close://'.$tmpFile,$mode); + } + } + + public function writeBack($tmpFile){ + if(isset(self::$tempFiles[$tmpFile])){ + $this->uploadFile($tmpFile,self::$tempFiles[$tmpFile]); + unlink($tmpFile); + } + } + + public function free_space($path){ + $path=$this->cleanPath($path); + try{ + $response=$this->client->propfind($path, array('{DAV:}quota-available-bytes')); + if(isset($response['{DAV:}quota-available-bytes'])){ + return (int)$response['{DAV:}quota-available-bytes']; + }else{ + return 0; + } + }catch(Exception $e){ + return 0; + } + } + + public function touch($path,$mtime=null){ + if(is_null($mtime)){ + $mtime=time(); + } + $path=$this->cleanPath($path); + $this->client->proppatch($path, array('{DAV:}lastmodified' => $mtime,)); + } + + public function getFile($path,$target){ + $source=$this->fopen($path,'r'); + file_put_contents($target,$source); + } + + public function uploadFile($path,$target){ + $source=fopen($path,'r'); + + $curl = curl_init(); + curl_setopt($curl,CURLOPT_USERPWD,$this->user.':'.$this->password); + curl_setopt($curl, CURLOPT_URL, $this->createBaseUri().$target); + curl_setopt($curl, CURLOPT_BINARYTRANSFER, true); + curl_setopt($curl, CURLOPT_INFILE, $source); // file pointer + curl_setopt($curl, CURLOPT_INFILESIZE, filesize($path)); + curl_setopt($curl, CURLOPT_PUT, true); + curl_exec ($curl); + curl_close ($curl); + } + + public function rename($path1,$path2){ + $path1=$this->cleanPath($path1); + $path2=$this->root.$this->cleanPath($path2); + try{ + $response=$this->client->request('MOVE',$path1,null,array('Destination'=>$path2)); + return true; + }catch(Exception $e){ + echo $e; + echo 'fail'; + var_dump($response); + return false; + } + } + + public function copy($path1,$path2){ + $path1=$this->cleanPath($path1); + $path2=$this->root.$this->cleanPath($path2); + try{ + $response=$this->client->request('COPY',$path1,null,array('Destination'=>$path2)); + return true; + }catch(Exception $e){ + echo $e; + echo 'fail'; + var_dump($response); + return false; + } + } + + public function stat($path){ + $path=$this->cleanPath($path); + try{ + $response=$this->client->propfind($path, array('{DAV:}getlastmodified','{DAV:}getcontentlength')); + if(isset($response['{DAV:}getlastmodified']) and isset($response['{DAV:}getcontentlength'])){ + return array( + 'mtime'=>strtotime($response['{DAV:}getlastmodified']), + 'size'=>(int)$response['{DAV:}getcontentlength'], + 'ctime'=>-1, + ); + }else{ + return array(); + } + }catch(Exception $e){ + return array(); + } + } + + public function getMimeType($path){ + $path=$this->cleanPath($path); + try{ + $response=$this->client->propfind($path, array('{DAV:}getcontenttype','{DAV:}resourcetype')); + $responseType=$response["{DAV:}resourcetype"]->resourceType; + $type=(count($responseType)>0 and $responseType[0]=="{DAV:}collection")?'dir':'file'; + if($type=='dir'){ + return 'httpd/unix-directory'; + }elseif(isset($response['{DAV:}getcontenttype'])){ + return $response['{DAV:}getcontenttype']; + }else{ + return false; + } + }catch(Exception $e){ + return false; + } + } + + private function cleanPath($path){ + if(substr($path,0,1)=='/'){ + return substr($path,1); + }else{ + return $path; + } + } + + private function simpleResponse($method,$path,$body,$expected){ + $path=$this->cleanPath($path); + try{ + $response=$this->client->request($method,$path,$body); + return $response['statusCode']==$expected; + }catch(Exception $e){ + return false; + } + } +} + diff --git a/apps/files_remote/tests/config.php b/apps/files_remote/tests/config.php index 5410578291..e2eea72f24 100644 --- a/apps/files_remote/tests/config.php +++ b/apps/files_remote/tests/config.php @@ -5,5 +5,11 @@ return array( 'user'=>'test', 'password'=>'test', 'root'=>'/test', - ) + ), + 'webdav'=>array( + 'host'=>'localhost', + 'user'=>'test', + 'password'=>'test', + 'root'=>'/owncloud/files/webdav.php', + ), ); diff --git a/apps/files_remote/tests/ftp.php b/apps/files_remote/tests/ftp.php index 2d5405ccda..03633b7c0d 100644 --- a/apps/files_remote/tests/ftp.php +++ b/apps/files_remote/tests/ftp.php @@ -7,9 +7,6 @@ */ class Test_Filestorage_FTP extends Test_FileStorage { - /** - * @var string tmpDir - */ private $config; private $id; @@ -24,5 +21,3 @@ class Test_Filestorage_FTP extends Test_FileStorage { OC_Helper::rmdirr($this->instance->constructUrl('')); } } - -?> \ No newline at end of file diff --git a/apps/files_remote/tests/webdav.php b/apps/files_remote/tests/webdav.php new file mode 100644 index 0000000000..219fff8852 --- /dev/null +++ b/apps/files_remote/tests/webdav.php @@ -0,0 +1,23 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +class Test_Filestorage_DAV extends Test_FileStorage { + private $config; + private $id; + + public function setUp(){ + $id=uniqid(); + $this->config=include('apps/files_remote/tests/config.php'); + $this->config['webdav']['root'].='/'.$id;//make sure we have an new empty folder to work in + $this->instance=new OC_Filestorage_DAV($this->config['webdav']); + } + + public function tearDown(){ + $this->instance->rmdir('/'); + } +} From cbdcb68c2b2bfed5d7ad3a1b0bf8b7f20210b258 Mon Sep 17 00:00:00 2001 From: Bartek Przybylski Date: Sat, 24 Mar 2012 18:35:16 +0100 Subject: [PATCH 103/132] gallery sharing, experimental version --- apps/gallery/ajax/galleryOp.php | 44 ++++++++++- apps/gallery/ajax/sharing.php | 118 ++++++++++++++++++++++++++++++ apps/gallery/appinfo/app.php | 1 + apps/gallery/appinfo/database.xml | 24 ++++++ apps/gallery/css/sharing.css | 8 ++ apps/gallery/css/styles.css | 2 + apps/gallery/img/breadcrumb.png | Bin 0 -> 220 bytes apps/gallery/index.php | 5 +- apps/gallery/js/album_cover.js | 46 +++++++++++- apps/gallery/js/albums.js | 5 +- apps/gallery/js/sharing.js | 57 +++++++++++++++ apps/gallery/lib/album.php | 2 +- apps/gallery/lib/photo.php | 5 +- apps/gallery/lib/sharing.php | 89 ++++++++++++++++++++++ apps/gallery/sharing.php | 47 ++++++++++++ apps/gallery/templates/index.php | 3 +- core/js/oc-dialogs.js | 20 +++-- 17 files changed, 457 insertions(+), 19 deletions(-) create mode 100644 apps/gallery/ajax/sharing.php create mode 100644 apps/gallery/css/sharing.css create mode 100644 apps/gallery/img/breadcrumb.png create mode 100644 apps/gallery/js/sharing.js create mode 100644 apps/gallery/lib/sharing.php create mode 100644 apps/gallery/sharing.php diff --git a/apps/gallery/ajax/galleryOp.php b/apps/gallery/ajax/galleryOp.php index 459c30f6ac..b0433898cd 100644 --- a/apps/gallery/ajax/galleryOp.php +++ b/apps/gallery/ajax/galleryOp.php @@ -111,9 +111,48 @@ function handleGetGallery($path) { $p[] = utf8_encode($r['file_path']); } - OC_JSON::success(array('albums'=>$a, 'photos'=>$p)); + $r = OC_Gallery_Sharing::getEntryByAlbumId($album_details['album_id']); + $shared = false; + $recursive = false; + $token = ''; + if ($row = $r->fetchRow()) { + $shared = true; + $recursive = ($row['recursive'] == 1)? true : false; + $token = $row['token']; + } + + OC_JSON::success(array('albums'=>$a, 'photos'=>$p, 'shared' => $shared, 'recursive' => $recursive, 'token' => $token)); } +function handleShare($path, $share, $recursive) { + $recursive = $recursive == 'true' ? 1 : 0; + $owner = OC_User::getUser(); + $r = OC_Gallery_Album::find($owner, null, $path); + if ($row = $r->fetchRow()) { + $albumId = $row['album_id']; + } else { + OC_JSON::error(array('cause' => 'Couldn\'t find requested gallery')); + exit; + } + + if ($share == false) { + OC_Gallery_Sharing::remove($albumId); + OC_JSON::success(array('sharing' => false)); + } else { // share, yeah \o/ + $r = OC_Gallery_Sharing::getEntryByAlbumId($albumId); + if (($row = $r->fetchRow())) { // update entry + OC_Gallery_Sharing::updateSharingByToken($row['token'], $recursive); + OC_JSON::success(array('sharing' => true, 'token' => $row['token'], 'recursive' => $recursive == 1 ? true : false )); + } else { // and new sharing entry + $date = new DateTime(); + $token = md5($owner . $date->getTimestamp()); + OC_Gallery_Sharing::addShared($token, intval($albumId), $recursive); + OC_JSON::success(array('sharing' => true, 'token' => $token, 'recursive' => $recursive == 1 ? true : false )); + } + } +} + + if ($_GET['operation']) { switch($_GET['operation']) { case 'rename': @@ -136,6 +175,9 @@ if ($_GET['operation']) { case 'get_gallery': handleGetGallery($_GET['path']); break; + case 'share': + handleShare($_GET['path'], $_GET['share'] == 'true' ? true : false, $_GET['recursive']); + break; default: OC_JSON::error(array('cause' => 'Unknown operation')); } diff --git a/apps/gallery/ajax/sharing.php b/apps/gallery/ajax/sharing.php new file mode 100644 index 0000000000..b737d8f6fe --- /dev/null +++ b/apps/gallery/ajax/sharing.php @@ -0,0 +1,118 @@ +. +* +*/ + +require_once('../../../lib/base.php'); + +if (!isset($_GET['token']) || !isset($_GET['operation'])) { + OC_JSON::error(array('cause' => 'Not enought arguments')); + exit; +} + +$operation = $_GET['operation']; +$token = $_GET['token']; + +if (!OC_Gallery_Sharing::isTokenValid($token)) { + OC_JSON::error(array('cause' => 'Given token is not valid')); + exit; +} + +function handleGetGallery($token, $path) { + $owner = OC_Gallery_Sharing::getTokenOwner($token); + $apath = OC_Gallery_Sharing::getPath($token); + + if ($path == false) + $root = $apath; + else + $root = rtrim($apath,'/').$path; + + $r = OC_Gallery_Album::find($owner, null, $root); + $albums = array(); + $photos = array(); + $albumId = -1; + if ($row = $r->fetchRow()) { + $albumId = $row['album_id']; + } + if ($albumId != -1) { + + if (OC_Gallery_Sharing::isRecursive($token)) { + $r = OC_Gallery_Album::find($owner, null, null, $root); + while ($row = $r->fetchRow()) + $albums[] = $row['album_name']; + } + + $r = OC_Gallery_Photo::find($albumId); + while ($row = $r->fetchRow()) + $photos[] = $row['file_path']; + } + + OC_JSON::success(array('albums' => $albums, 'photos' => $photos)); +} + +function handleGetThumbnail($token, $imgpath) { + $owner = OC_Gallery_Sharing::getTokenOwner($token); + $image = OC_Gallery_Photo::getThumbnail($imgpath, $owner); + if ($image) { + OC_Response::enableCaching(3600 * 24); // 24 hour + $image->show(); + } +} + +function handleGetAlbumThumbnail($token, $albumname) +{ + $owner = OC_Gallery_Sharing::getTokenOwner($token); + $file = OC_Config::getValue("datadirectory").'/'. $owner .'/gallery/'.$albumname.'.png'; + $image = new OC_Image($file); + if ($image->valid()) { + $image->centerCrop(); + $image->resize(200); + $image->fixOrientation(); + OC_Response::enableCaching(3600 * 24); // 24 hour + $image->show(); + } +} + +function handleGetPhoto($token, $photo) { + $owner = OC_Gallery_Sharing::getTokenOwner($token); + if (OC_User::isLoggedIn()) + $file = OC::$CONFIG_DATADIRECTORY.urldecode($photo); + else + $file = OC::$CONFIG_DATADIRECTORY.'/'.$owner.'/files'.urldecode($photo); + header('Content-Type: '.OC_Image::getMimeTypeForFile($file)); + OC_Response::sendFile($file); +} + +switch ($operation) { + case 'get_gallery': + handleGetGallery($token, isset($_GET['path'])? $_GET['path'] : false); + break; + case 'get_thumbnail': + handleGetThumbnail($token, urldecode($_GET['img'])); + break; + case 'get_album_thumbnail': + handleGetAlbumThumbnail($token, urldecode($_GET['albumname'])); + break; + case 'get_photo': + handleGetPhoto($token, urldecode($_GET['photo'])); + break; +} + diff --git a/apps/gallery/appinfo/app.php b/apps/gallery/appinfo/app.php index 1e5e27d408..3e7e38301c 100644 --- a/apps/gallery/appinfo/app.php +++ b/apps/gallery/appinfo/app.php @@ -24,6 +24,7 @@ OC::$CLASSPATH['OC_Gallery_Album'] = 'apps/gallery/lib/album.php'; OC::$CLASSPATH['OC_Gallery_Photo'] = 'apps/gallery/lib/photo.php'; OC::$CLASSPATH['OC_Gallery_Scanner'] = 'apps/gallery/lib/scanner.php'; +OC::$CLASSPATH['OC_Gallery_Sharing'] = 'apps/gallery/lib/sharing.php'; OC::$CLASSPATH['OC_Gallery_Hooks_Handlers'] = 'apps/gallery/lib/hooks_handlers.php'; $l = new OC_L10N('gallery'); diff --git a/apps/gallery/appinfo/database.xml b/apps/gallery/appinfo/database.xml index 62fdbee9cd..e3b13f7e93 100644 --- a/apps/gallery/appinfo/database.xml +++ b/apps/gallery/appinfo/database.xml @@ -67,4 +67,28 @@
      + + *dbprefix*gallery_sharing + + + token + text + true + 64 + + + gallery_id + integer + 0 + true + 4 + + + recursive + integer + true + 1 + + +
      diff --git a/apps/gallery/css/sharing.css b/apps/gallery/css/sharing.css new file mode 100644 index 0000000000..eaac82ebd6 --- /dev/null +++ b/apps/gallery/css/sharing.css @@ -0,0 +1,8 @@ +body { background-color: #eee; margin: 0; padding: 0;} +#gallery_list { height: 100%; width: 80%; background-color: white; margin: 0 auto; box-shadow: 0 0 8px #888; } +div.gallery_box { width: 200px; position:relative; text-align: center; border: 0; display: inline-block; margin: 5pt; vertical-align: top; padding: 5px 5px 5px 5px; position: relative; cursor: pointer; -webkit-transition: color 0.5s ease-in-out; -o-transition: color 0.5s ease-in-out; -moz-transition: color 0.5s ease-in-out;color: #BBB;} +div.gallery_box:hover { color: black; } +div.gallery_box h1 {font-size: 17px; font-weight: normal;} +div#breadcrumb { border: 0; width: 70%; margin: 0 auto; padding: 25px 0; font-family: Verdana; text-align: center;} +span.breadcrumbelement { margin: 10px; margin-right: 0; cursor: pointer;} +span.inside { background-image: url('../img/breadcrumb.png'); padding-left: 20px; background-position: left; background-repeat: no-repeat;} diff --git a/apps/gallery/css/styles.css b/apps/gallery/css/styles.css index 013cd1b262..fbf54e43db 100644 --- a/apps/gallery/css/styles.css +++ b/apps/gallery/css/styles.css @@ -16,3 +16,5 @@ div.gallery_control_overlay a { color:white; } #g-settings {position: absolute; left 13.5em; top: 0;} input[type=button] { -webkit-transition: opacity 0.5s ease-in-out; -moz-transition: opacity 0.5s ease-in-out; -o-transition: opacity 0.5s ease-in-out; opacity: 1} input[type=button]:disabled { opacity: 0.5 } +.ui-dialog tr {background-color: #eee;} +.ui-dialog input {width: 90%;} diff --git a/apps/gallery/img/breadcrumb.png b/apps/gallery/img/breadcrumb.png new file mode 100644 index 0000000000000000000000000000000000000000..a252a751554e142eb9dda6daecf529b41ffb0bed GIT binary patch literal 220 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`EX7WqAsj$Z!;#Vf2?p zUk71ECym(^Ktah8*NBqf{Irtt#G+J&^73-M%)IR4

      '; + + for (var i in r.albums) { + var a = r.albums[i]; + var local = $(album_template.replace('IMGPATH', encodeURIComponent(a))); + local.attr('title', a); + $('h1', local).html(a); + element.append(local); + } + + $('div.gallery_box').each(function(i, element) { + $(element).click(function() { + paths.push($(this).attr('title')); + path = ''; + for (var e in paths) path += '/' + paths[e]; + $.getJSON('ajax/sharing.php', {operation: 'get_gallery', token: TOKEN, path: path}, function(r) { + var name = paths[paths.length-1]; + counter++; + var d = ''+name+''; + d = $(d).addClass('inside'); + $('#breadcrumb').append(d); + albumClickHandler(r); + }); + }); + }); + + var pat = ''; + for (var a in paths) pat += '/'+paths[a]; + var photo_template = ''; + for (var a in r.photos) { + var local = photo_template.replace('IMGPATH', encodeURIComponent(r.photos[a])).replace('*HREF*', 'ajax/sharing.php?token='+TOKEN+'&operation=get_photo&photo='+encodeURIComponent(r.photos[a])); + element.append(local); + } +} diff --git a/apps/gallery/lib/album.php b/apps/gallery/lib/album.php index 070afdd6cd..ef361a3791 100644 --- a/apps/gallery/lib/album.php +++ b/apps/gallery/lib/album.php @@ -79,7 +79,7 @@ class OC_Gallery_Album { $sql .= ' AND parent_path = ?'; $args[] = $parent; } - $order = OC_Preferences::getValue(OC_User::getUser(), 'gallery', 'order', 'ASC'); + $order = OC_Preferences::getValue($owner, 'gallery', 'order', 'ASC'); $sql .= ' ORDER BY album_name ' . $order; $stmt = OC_DB::prepare($sql); diff --git a/apps/gallery/lib/photo.php b/apps/gallery/lib/photo.php index 5e6df8069b..0c0f16e659 100644 --- a/apps/gallery/lib/photo.php +++ b/apps/gallery/lib/photo.php @@ -66,8 +66,9 @@ class OC_Gallery_Photo { $stmt->execute(array($newpath, $newAlbumId, $oldAlbumId, $oldpath)); } - public static function getThumbnail($image_name) { - $save_dir = OC_Config::getValue("datadirectory").'/'. OC_User::getUser() .'/gallery/'; + public static function getThumbnail($image_name, $owner = null) { + if (!$owner) $owner = OC_User::getUser(); + $save_dir = OC_Config::getValue("datadirectory").'/'. $owner .'/gallery/'; $save_dir .= dirname($image_name). '/'; $image_path = $image_name; $thumb_file = $save_dir . basename($image_name); diff --git a/apps/gallery/lib/sharing.php b/apps/gallery/lib/sharing.php new file mode 100644 index 0000000000..60f108bd6c --- /dev/null +++ b/apps/gallery/lib/sharing.php @@ -0,0 +1,89 @@ +. +* +*/ + +class OC_Gallery_Sharing { + private static function getEntries($token) { + $sql = 'SELECT * FROM *PREFIX*gallery_sharing WHERE token = ?'; + $stmt = OC_DB::prepare($sql); + return $stmt->execute(array($token)); + } + + public static function isTokenValid($token) { + $r = self::getEntries($token); + $row = $r->fetchRow(); + return $row != null; + } + + public static function isRecursive($token) { + $r = self::getEntries($token); + if ($row = $r->fetchRow()) return $row['recursive'] == 1; + return false; + } + + public static function getTokenOwner($token) { + $r = self::getEntries($token); + if ($row = $r->fetchRow()) { + $galleryId = $row['gallery_id']; + $sql = 'SELECT * FROM *PREFIX*gallery_albums WHERE album_id = ?'; + $stmt = OC_DB::prepare($sql); + $r = $stmt->execute(array($galleryId)); + if ($row = $r->fetchRow()) + return $row['uid_owner']; + } + return false; + } + + public static function getPath($token) { + $r = self::getEntries($token); + if ($row = $r->fetchRow()) { + $galleryId = $row['gallery_id']; + $sql = 'SELECT * FROM *PREFIX*gallery_albums WHERE album_id = ?'; + $stmt = OC_DB::prepare($sql); + $r = $stmt->execute(array($galleryId)); + if ($row = $r->fetchRow()) + return $row['album_path']; + } + } + + public static function updateSharingByToken($token, $recursive) { + $stmt = OC_DB::prepare('UPDATE *PREFIX*gallery_sharing SET recursive = ? WHERE token = ?'); + $stmt->execute(array($recursive, $token)); + } + + public static function getEntryByAlbumId($album_id) { + $stmt = OC_DB::prepare('SELECT * FROM *PREFIX*gallery_sharing WHERE gallery_id = ?'); + return $stmt->execute(array($album_id)); + } + + public static function addShared($token, $albumId, $recursive) { + $sql = 'INSERT INTO *PREFIX*gallery_sharing (token, gallery_id, recursive) VALUES (?, ?, ?)'; + $stmt = OC_DB::prepare($sql); + $stmt->execute(array($token, $albumId, $recursive)); + } + + public static function remove($albumId) { + $stmt = OC_DB::prepare('DELETE FROM *PREFIX*gallery_sharing WHERE gallery_id = ?'); + $stmt->execute(array($albumId)); + } +} + diff --git a/apps/gallery/sharing.php b/apps/gallery/sharing.php new file mode 100644 index 0000000000..d7430becf4 --- /dev/null +++ b/apps/gallery/sharing.php @@ -0,0 +1,47 @@ +. +* +*/ + +if (!isset($_GET['token']) || empty($_GET['token'])) { + exit; +} + +require_once('../../lib/base.php'); + +OC_Util::checkAppEnabled('gallery'); + +?> + + + + + + + + + + + + + diff --git a/apps/gallery/templates/index.php b/apps/gallery/templates/index.php index dc5852733b..c6373d3b0a 100644 --- a/apps/gallery/templates/index.php +++ b/apps/gallery/templates/index.php @@ -14,7 +14,8 @@ $l = new OC_L10N('gallery');
      - + +
      diff --git a/core/js/oc-dialogs.js b/core/js/oc-dialogs.js index 9ce2bae164..c11ac13332 100644 --- a/core/js/oc-dialogs.js +++ b/core/js/oc-dialogs.js @@ -2,7 +2,7 @@ * ownCloud * * @author Bartek Przybylski - * @copyright 2012 Bartek Przybylski bart.p.pl@gmail.com + * @copyright 2012 Bartek Przybylski bartek@alefzero.eu * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE @@ -66,7 +66,7 @@ OCdialogs = { }, /** * prompt user for input with custom form - * fields should be passed in following format: [{text:'prompt text', name:'return name', type:'input type'},...] + * fields should be passed in following format: [{text:'prompt text', name:'return name', type:'input type', value: 'dafault value'},...] * @param fields to display * @param title dialog title * @param callback which will be triggered when user press OK (user answers will be passed to callback in following format: [{name:'return name', value: 'user value'},...]) @@ -76,8 +76,15 @@ OCdialogs = { for (var a in fields) { content += ''+fields[a].text+''; var type=fields[a].type; - if (type == 'text' || type == 'checkbox' || type == 'password') - content += ''; + if (type == 'text' || type == 'checkbox' || type == 'password') { + content += ''; + } content += "" } content += ""; @@ -112,7 +119,8 @@ OCdialogs = { b[0] = {text: t('dialogs', 'Ok'), click: f}; break; } - $(c_id).dialog({width: 4*$(document).width()/9, height: $(d).height() + 150, modal: false, buttons: b}); + var possible_height = ($('tr', d).size()+1)*30; + $(c_id).dialog({width: 4*$(document).width()/9, height: possible_height + 120, modal: false, buttons: b}); OCdialogs.dialogs_counter++; }, // dialogs buttons types @@ -127,7 +135,7 @@ OCdialogs = { dialogs_counter: 0, determineValue: function(element) { switch ($(element).attr('type')) { - case 'checkbox': return $(element).attr('checked') != undefined; + case 'checkbox': return element.checked; } return $(element).val(); }, From afcf96549883e1ac9b87681ac7d5d0c3ea0cd513 Mon Sep 17 00:00:00 2001 From: Bartek Przybylski Date: Sat, 24 Mar 2012 18:40:27 +0100 Subject: [PATCH 104/132] fixup: sharing gallery for loggedin users fail --- apps/gallery/ajax/sharing.php | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/apps/gallery/ajax/sharing.php b/apps/gallery/ajax/sharing.php index b737d8f6fe..fba85fa34e 100644 --- a/apps/gallery/ajax/sharing.php +++ b/apps/gallery/ajax/sharing.php @@ -93,10 +93,7 @@ function handleGetAlbumThumbnail($token, $albumname) function handleGetPhoto($token, $photo) { $owner = OC_Gallery_Sharing::getTokenOwner($token); - if (OC_User::isLoggedIn()) - $file = OC::$CONFIG_DATADIRECTORY.urldecode($photo); - else - $file = OC::$CONFIG_DATADIRECTORY.'/'.$owner.'/files'.urldecode($photo); + $file = OC_Config::getValue( "datadirectory", OC::$SERVERROOT."/data" ).'/'.$owner.'/files'.urldecode($photo); header('Content-Type: '.OC_Image::getMimeTypeForFile($file)); OC_Response::sendFile($file); } From be60b451eb7a152f19e31eeaf1b2f009eadb1a6b Mon Sep 17 00:00:00 2001 From: Bartek Przybylski Date: Sat, 24 Mar 2012 19:21:36 +0100 Subject: [PATCH 105/132] fix albums thumbnails preview for opera --- apps/gallery/js/albums.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/gallery/js/albums.js b/apps/gallery/js/albums.js index be121b2d70..1fb38a5546 100644 --- a/apps/gallery/js/albums.js +++ b/apps/gallery/js/albums.js @@ -67,14 +67,14 @@ Albums={ $(".gallery_album_cover", local).css('background-repeat', 'no-repeat'); $(".gallery_album_cover", local).css('background-position', '0'); $(".gallery_album_cover", local).css('background-image','url("'+OC.filePath('gallery','ajax','galleryOp.php')+'?operation=get_covers&albumname='+escape(a.name)+'")'); - $(".gallery_album_cover", local).mousemove(function(e) { + $(".gallery_album_cover", local).mousemove(function(event) { var albumMetadata = Albums.find(this.title); if (albumMetadata == undefined) { return; } - var x = Math.floor((e.layerX - this.offsetLeft)/(this.offsetWidth/albumMetadata.numOfCovers)); + var x = Math.floor(event.offsetX/(this.offsetWidth/albumMetadata.numOfCovers)); x *= this.offsetWidth; - if (x < 0) x=0; + if (x < 0 || isNaN(x)) x=0; $(this).css('background-position', -x+'px 0'); }); $(element).append(local); From 826cb2c650d9a9c1b8d826cba6863dbfacc8b8f4 Mon Sep 17 00:00:00 2001 From: Bartek Przybylski Date: Sat, 24 Mar 2012 19:26:53 +0100 Subject: [PATCH 106/132] fix sharing address construction in opera and firefox --- apps/gallery/js/album_cover.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/apps/gallery/js/album_cover.js b/apps/gallery/js/album_cover.js index 41a648bec5..061bbcd0b4 100644 --- a/apps/gallery/js/album_cover.js +++ b/apps/gallery/js/album_cover.js @@ -30,10 +30,14 @@ function albumClick(title) { }); } +function constructSharingPath() { + return document.location.protocol + '//' + document.location.host + OC.linkTo('gallery', 'sharing.php') + '?token=' + Albums.token; +} + function shareGallery() { var existing_token = ''; if (Albums.token) - existing_token = document.location.origin + OC.linkTo('gallery', 'sharing.php') + '?token=' + Albums.token; + existing_token = constructSharingPath(); var form_fields = [{text: 'Share', name: 'share', type: 'checkbox', value: Albums.shared}, {text: 'Share recursive', name: 'recursive', type: 'checkbox', value: Albums.recursive}, {text: 'Shared gallery address', name: 'address', type: 'text', value: existing_token}]; @@ -53,7 +57,7 @@ function shareGallery() { } var actual_addr = ''; if (Albums.token) - actual_addr = document.location.origin + OC.linkTo('gallery', 'sharing.php') + '?token=' + Albums.token; + actual_addr = constructSharingPath(); $('input[name="address"]').val(actual_addr); } else { OC.dialogs.alert(t('gallery', 'Error: ') + r.cause, t('gallery', 'Internal error')); From 26fcb35a899fd8566a0e709dfd6b1f8a7d01094c Mon Sep 17 00:00:00 2001 From: Michael Gapczynski Date: Sat, 24 Mar 2012 14:49:44 -0400 Subject: [PATCH 107/132] Implement fopen() for Google Docs storage backend --- lib/filestorage/google.php | 122 +++++++++++++++++++++++++++++-------- 1 file changed, 96 insertions(+), 26 deletions(-) diff --git a/lib/filestorage/google.php b/lib/filestorage/google.php index 4998554838..5de47650f6 100644 --- a/lib/filestorage/google.php +++ b/lib/filestorage/google.php @@ -40,7 +40,7 @@ class OC_Filestorage_Google extends OC_Filestorage_Common { $this->entries = array(); } - private function sendRequest($feedUri, $http_method, $postData = null) { + private function sendRequest($feedUri, $http_method, $isDownload = false, $postData = null) { $feedUri = trim($feedUri); // create an associative array from each key/value url query param pair. $params = array(); @@ -54,30 +54,71 @@ class OC_Filestorage_Google extends OC_Filestorage_Common { $tempStr .= '&' . urlencode($key) . '=' . urlencode($value); } $feedUri = preg_replace('/&/', '?', $tempStr, 1); - $req = OAuthRequest::from_consumer_and_token($this->consumer, $this->oauth_token, $http_method, $feedUri, $params); - $req->sign_request($this->sig_method, $this->consumer, $this->oauth_token); - $auth_header = $req->to_header(); - $result = send_signed_request($http_method, $feedUri, array($auth_header, 'Content-Type: application/atom+xml', 'GData-Version: 3.0'), $postData); - // TODO Return false if error is received - if (!$result) { - return false; + $request = OAuthRequest::from_consumer_and_token($this->consumer, $this->oauth_token, $http_method, $feedUri, $params); + $request->sign_request($this->sig_method, $this->consumer, $this->oauth_token); + $auth_header = $request->to_header(); + $headers = array($auth_header, 'Content-Type: application/atom+xml', 'GData-Version: 3.0'); + $curl = curl_init($feedUri); + curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); + curl_setopt($curl, CURLOPT_FAILONERROR, false); + curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false); + switch ($http_method) { + case 'GET': + curl_setopt($curl, CURLOPT_HTTPHEADER, $headers); + break; + case 'POST': + curl_setopt($curl, CURLOPT_HTTPHEADER, $headers); + curl_setopt($curl, CURLOPT_POST, 1); + curl_setopt($curl, CURLOPT_POSTFIELDS, $postData); + break; + case 'PUT': + $headers[] = 'If-Match: *'; + curl_setopt($curl, CURLOPT_HTTPHEADER, $headers); + curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $http_method); + curl_setopt($curl, CURLOPT_POSTFIELDS, $postData); + break; + case 'DELETE': + $headers[] = 'If-Match: *'; + curl_setopt($curl, CURLOPT_HTTPHEADER, $headers); + curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $http_method); + break; + default: + curl_setopt($curl, CURLOPT_HTTPHEADER, $headers); } - $result = explode('<', $result, 2); - $result = isset($result[1]) ? '<'.$result[1] : $result[0]; + if ($isDownload) { + $tmpFile = OC_Helper::tmpFile(); + $fp = fopen($tmpFile, 'w'); + curl_setopt($curl, CURLOPT_FILE, $fp); + curl_exec($curl); + curl_close($curl); + return $tmpFile; + } + $result = curl_exec($curl); + curl_close($curl); $dom = new DOMDocument(); $dom->loadXML($result); return $dom; } private function getResource($path) { - if (array_key_exists($path, $this->entries)) { - return $this->entries[$path]; + $file = basename($path); + if (array_key_exists($file, $this->entries)) { + return $this->entries[$file]; } else { - $title = basename($path); - $dom = $this->sendRequest('https://docs.google.com/feeds/default/private/full?showfolders=true&title='.$title, 'GET'); + // Strip the file extension; file could be a native Google Docs resource + if ($pos = strpos($file, '.')) { + $title = substr($file, 0, $pos); + $dom = $this->sendRequest('https://docs.google.com/feeds/default/private/full?showfolders=true&title='.$title, 'GET'); + // Check if request was successful and entry exists + if ($dom && $entry = $dom->getElementsByTagName('entry')->item(0)) { + $this->entries[$file] = $entry; + return $entry; + } + } + $dom = $this->sendRequest('https://docs.google.com/feeds/default/private/full?showfolders=true&title='.$file, 'GET'); // Check if request was successful and entry exists if ($dom && $entry = $dom->getElementsByTagName('entry')->item(0)) { - $this->entries[$path] = $entry; + $this->entries[$file] = $entry; return $entry; } return false; @@ -86,7 +127,7 @@ class OC_Filestorage_Google extends OC_Filestorage_Common { private function getExtension($entry) { $mimetype = $this->getMimeType('', $entry); - switch($mimetype) { + switch ($mimetype) { case 'httpd/unix-directory': return ''; case 'application/vnd.oasis.opendocument.text': @@ -158,7 +199,10 @@ class OC_Filestorage_Google extends OC_Filestorage_Common { $name = $entry->getElementsByTagName('title')->item(0)->nodeValue; // Google Docs resources don't always include extensions in title if (!strpos($name, '.')) { - $name .= '.'.$this->getExtension($entry); + $extension = $this->getExtension($entry); + if ($extension != '') { + $name .= '.'.$extension; + } } $files[] = $name; // Cache entry for future use @@ -178,11 +222,15 @@ class OC_Filestorage_Google extends OC_Filestorage_Common { } else if ($entry = $this->getResource($path)) { // NOTE: Native resources don't have a file size $stat['size'] = $entry->getElementsByTagNameNS('http://schemas.google.com/g/2005', 'quotaBytesUsed')->item(0)->nodeValue; - $stat['atime'] = strtotime($entry->getElementsByTagNameNS('http://schemas.google.com/g/2005', 'lastViewed')->item(0)->nodeValue); +// if (isset($atime = $entry->getElementsByTagNameNS('http://schemas.google.com/g/2005', 'lastViewed')->item(0)->nodeValue)) +// $stat['atime'] = strtotime($entry->getElementsByTagNameNS('http://schemas.google.com/g/2005', 'lastViewed')->item(0)->nodeValue); $stat['mtime'] = strtotime($entry->getElementsByTagName('updated')->item(0)->nodeValue); $stat['ctime'] = strtotime($entry->getElementsByTagName('published')->item(0)->nodeValue); } - return $stat; + if (isset($stat)) { + return $stat; + } + return false; } public function filetype($path) { @@ -278,14 +326,36 @@ class OC_Filestorage_Google extends OC_Filestorage_Common { public function fopen($path, $mode) { if ($entry = $this->getResource($path)) { - $extension = $this->getExtension($path); - $downloadUri = $entry->getElementsByTagName('content')->item(0)->getAttribute('src'); - // TODO Non-native documents don't need these additional parameters - $downloadUri .= '&exportFormat='.$extension.'&format='.$extension; + switch ($mode) { + case 'r': + case 'rb': + $extension = $this->getExtension($entry); + $downloadUri = $entry->getElementsByTagName('content')->item(0)->getAttribute('src'); + // TODO Non-native documents don't need these additional parameters + $downloadUri .= '&exportFormat='.$extension.'&format='.$extension; + $tmpFile = $this->sendRequest($downloadUri, 'GET', true); + return fopen($tmpFile, 'r'); + case 'w': + case 'wb': + case 'a': + case 'ab': + case 'r+': + case 'w+': + case 'wb+': + case 'a+': + case 'x': + case 'x+': + case 'c': + case 'c+': + // TODO Edit documents + } + } + return false; } public function getMimeType($path, $entry = null) { + // Entry can be passed, because extension is required for opendir and the entry can't be cached without the extension if ($entry == null) { if ($path == '' || $path == '/') { return 'httpd/unix-directory'; @@ -297,7 +367,7 @@ class OC_Filestorage_Google extends OC_Filestorage_Common { $mimetype = $entry->getElementsByTagName('content')->item(0)->getAttribute('type'); // Native Google Docs resources often default to text/html, but it may be more useful to default to a corresponding ODF mimetype // Collections get reported as application/atom+xml, make sure it actually is a folder and fix the mimetype - if ($mimetype == 'text/html' || $mimetype == 'application/atom+xml') { + if ($mimetype == 'text/html' || $mimetype == 'application/atom+xml;type=feed') { $categories = $entry->getElementsByTagName('category'); foreach ($categories as $category) { if ($category->getAttribute('scheme') == 'http://schemas.google.com/g/2005#kind') { @@ -334,8 +404,8 @@ class OC_Filestorage_Google extends OC_Filestorage_Common { return false; } - public function search($query) { - + public function touch($path, $mtime = null) { + } } \ No newline at end of file From a3125f164e3bb882ab25f42fee4da9aa691ed8bb Mon Sep 17 00:00:00 2001 From: Bartek Przybylski Date: Sat, 24 Mar 2012 19:53:39 +0100 Subject: [PATCH 108/132] bookmarks tag placement & list width fix --- apps/bookmarks/js/bookmarks.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/apps/bookmarks/js/bookmarks.js b/apps/bookmarks/js/bookmarks.js index 3557810d4b..a3a4779d26 100644 --- a/apps/bookmarks/js/bookmarks.js +++ b/apps/bookmarks/js/bookmarks.js @@ -9,9 +9,7 @@ $(document).ready(function() { fillWindow($('.bookmarks_list')); }); $(window).resize(); - $($('.bookmarks_list')).scroll(updateOnBottom); - - $('.bookmarks_list').empty(); + $('.bookmarks_list').scroll(updateOnBottom).empty().width($('#content').width()); getBookmarks(); }); From c23090b43c6729cde99b073fac6653185b96d4d0 Mon Sep 17 00:00:00 2001 From: Bartek Przybylski Date: Sat, 24 Mar 2012 19:54:54 +0100 Subject: [PATCH 109/132] spaces to tabs in bookmarks --- apps/bookmarks/js/bookmarks.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/bookmarks/js/bookmarks.js b/apps/bookmarks/js/bookmarks.js index a3a4779d26..9502af0a00 100644 --- a/apps/bookmarks/js/bookmarks.js +++ b/apps/bookmarks/js/bookmarks.js @@ -9,7 +9,7 @@ $(document).ready(function() { fillWindow($('.bookmarks_list')); }); $(window).resize(); - $('.bookmarks_list').scroll(updateOnBottom).empty().width($('#content').width()); + $('.bookmarks_list').scroll(updateOnBottom).empty().width($('#content').width()); getBookmarks(); }); From d139e3c3cd19103cdb798f2fc80a1a461ac08615 Mon Sep 17 00:00:00 2001 From: Michael Gapczynski Date: Sat, 24 Mar 2012 15:27:42 -0400 Subject: [PATCH 110/132] Move Google Docs storage backend to files_remote app --- apps/files_remote/appinfo/app.php | 1 + {lib/filestorage => apps/files_remote/lib}/google.php | 2 -- apps/files_remote/tests/config.php | 7 +++++++ 3 files changed, 8 insertions(+), 2 deletions(-) rename {lib/filestorage => apps/files_remote/lib}/google.php (99%) diff --git a/apps/files_remote/appinfo/app.php b/apps/files_remote/appinfo/app.php index 25473d87fe..02c1c3ae31 100644 --- a/apps/files_remote/appinfo/app.php +++ b/apps/files_remote/appinfo/app.php @@ -8,3 +8,4 @@ OC::$CLASSPATH['OC_Filestorage_FTP']='apps/files_remote/lib/ftp.php'; OC::$CLASSPATH['OC_Filestorage_DAV']='apps/files_remote/lib/webdav.php'; +OC::$CLASSPATH['OC_Filestorage_Google']='apps/files_remote/lib/google.php'; diff --git a/lib/filestorage/google.php b/apps/files_remote/lib/google.php similarity index 99% rename from lib/filestorage/google.php rename to apps/files_remote/lib/google.php index 5de47650f6..0d6db1987f 100644 --- a/lib/filestorage/google.php +++ b/apps/files_remote/lib/google.php @@ -24,14 +24,12 @@ require_once 'common.inc.php'; class OC_Filestorage_Google extends OC_Filestorage_Common { - private $datadir; private $consumer; private $oauth_token; private $sig_method; private $entries; public function __construct($arguments) { - $this->datadir = $arguments['datadir']; $consumer_key = isset($arguments['consumer_key']) ? $arguments['consumer_key'] : 'anonymous'; $consumer_secret = isset($arguments['consumer_secret']) ? $arguments['consumer_secret'] : 'anonymous'; $this->consumer = new OAuthConsumer($consumer_key, $consumer_secret); diff --git a/apps/files_remote/tests/config.php b/apps/files_remote/tests/config.php index e2eea72f24..9b40d2b98c 100644 --- a/apps/files_remote/tests/config.php +++ b/apps/files_remote/tests/config.php @@ -12,4 +12,11 @@ return array( 'password'=>'test', 'root'=>'/owncloud/files/webdav.php', ), + 'google'=>array( + 'consumer_key'=>'anonymous', + 'consumer_secret'=>'anonymous', + 'token'=>'test', + 'token_secret'=>'test', + 'root'=>'/google', + ) ); From 34c08b3165ff7ee024006b4c425130fde057863c Mon Sep 17 00:00:00 2001 From: Michael Gapczynski Date: Sat, 24 Mar 2012 15:46:28 -0400 Subject: [PATCH 111/132] Add test for Google Docs storage backend, tester needs to token and token secret to config --- apps/files_remote/tests/google.php | 38 ++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 apps/files_remote/tests/google.php diff --git a/apps/files_remote/tests/google.php b/apps/files_remote/tests/google.php new file mode 100644 index 0000000000..b49f9e4647 --- /dev/null +++ b/apps/files_remote/tests/google.php @@ -0,0 +1,38 @@ +. +*/ + +class Test_Filestorage_Google extends Test_FileStorage { + + private $config; + private $id; + + public function setUp(){ + $id=uniqid(); + $this->config=include('apps/files_remote/tests/config.php'); + $this->config['google']['root'].='/'.$id;//make sure we have an new empty folder to work in + $this->instance=new OC_Filestorage_Google($this->config['google']); + } + + public function tearDown(){ + $this->instance->rmdir('/'); + } +} \ No newline at end of file From ec40f69c9e7a6aba39bd74ff1549e70a93357e4f Mon Sep 17 00:00:00 2001 From: Georg Ehrke Date: Sun, 25 Mar 2012 14:16:39 +0200 Subject: [PATCH 112/132] add error 403 site --- .htaccess | 1 + core/templates/403.php | 15 +++++++++++++++ 2 files changed, 16 insertions(+) create mode 100644 core/templates/403.php diff --git a/.htaccess b/.htaccess index ebb28b0887..11520d743d 100644 --- a/.htaccess +++ b/.htaccess @@ -1,3 +1,4 @@ +ErrorDocument 403 /core/templates/403.php ErrorDocument 404 /core/templates/404.php php_value upload_max_filesize 512M diff --git a/core/templates/403.php b/core/templates/403.php new file mode 100644 index 0000000000..cdfef08ac7 --- /dev/null +++ b/core/templates/403.php @@ -0,0 +1,15 @@ +printPage(); + exit; +} +?> +
        +
      • + t( 'Access forbidden' ); ?>
        +

        +
      • +
      From 102cf150b3a1de43877878debf9aef5f386d543b Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Mon, 26 Mar 2012 02:04:34 +0200 Subject: [PATCH 113/132] Fixed error in OC_Contacts_VCard::addFromDAVData as pointed out by Guillaume ZITTA --- apps/contacts/lib/vcard.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/contacts/lib/vcard.php b/apps/contacts/lib/vcard.php index 3736f18c64..15a6176d40 100644 --- a/apps/contacts/lib/vcard.php +++ b/apps/contacts/lib/vcard.php @@ -228,7 +228,7 @@ class OC_Contacts_VCard{ * @param string $uri the uri of the card, default based on the UID * @return insertid on success or null if no card. */ - public static function add($aid, $card, $uri=null){ + public static function add($aid, OC_VObject $card, $uri=null){ if(is_null($card)){ OC_Log::write('contacts','OC_Contacts_VCard::add. No vCard supplied', OC_Log::ERROR); return null; @@ -267,7 +267,7 @@ class OC_Contacts_VCard{ */ public static function addFromDAVData($id,$uri,$data){ $card = OC_VObject::parse($data); - return self::add($id, $data, $uri); + return self::add($id, $card, $uri); } /** From 6ff89dcf727ab140c766c093b6f91b92a50ef7e9 Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Mon, 26 Mar 2012 19:13:48 +0200 Subject: [PATCH 114/132] Removed obsolete code. --- apps/contacts/ajax/addproperty.php | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/apps/contacts/ajax/addproperty.php b/apps/contacts/ajax/addproperty.php index e1a3129283..d2c0291e8c 100644 --- a/apps/contacts/ajax/addproperty.php +++ b/apps/contacts/ajax/addproperty.php @@ -122,13 +122,4 @@ if(!OC_Contacts_VCard::edit($id,$vcard)) { exit(); } -$adr_types = OC_Contacts_App::getTypesOfProperty('ADR'); -$phone_types = OC_Contacts_App::getTypesOfProperty('TEL'); - -$tmpl = new OC_Template('contacts','part.property'); -$tmpl->assign('adr_types',$adr_types); -$tmpl->assign('phone_types',$phone_types); -$tmpl->assign('property',OC_Contacts_VCard::structureProperty($property,$line)); -$page = $tmpl->fetchPage(); - -OC_JSON::success(array('data' => array( 'checksum' => $checksum, 'page' => $page ))); +OC_JSON::success(array('data' => array( 'checksum' => $checksum ))); From 31e20d22834fd492f97ae38e6919f798ab6be932 Mon Sep 17 00:00:00 2001 From: Georg Ehrke Date: Mon, 26 Mar 2012 21:45:51 +0200 Subject: [PATCH 115/132] added some authors to the Authors file --- AUTHORS | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/AUTHORS b/AUTHORS index 02439884d2..f618df9311 100644 --- a/AUTHORS +++ b/AUTHORS @@ -5,6 +5,13 @@ ownCloud is written by: Jan-Christoph Borchardt Michael Gapczynski Arthur Schiwon + Bart Visscher + Georg Ehrke + Brice Maron + Tom Needham + Marvin Thomas Rabe + Florian Pritz + Bartek Przybylski … With help from many libraries and frameworks including: From ee31bc7995eaef0741dc1579d8b6b7e58f359ce4 Mon Sep 17 00:00:00 2001 From: Bart Visscher Date: Mon, 26 Mar 2012 21:46:18 +0200 Subject: [PATCH 116/132] Contacts: Fix saveproperty for categories --- apps/contacts/ajax/saveproperty.php | 19 ++++++++++++++++++- apps/contacts/templates/part.contact.php | 2 +- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/apps/contacts/ajax/saveproperty.php b/apps/contacts/ajax/saveproperty.php index 95a7ac2019..272a3f9b32 100644 --- a/apps/contacts/ajax/saveproperty.php +++ b/apps/contacts/ajax/saveproperty.php @@ -83,16 +83,34 @@ if($element != $name) { bailOut(OC_Contacts_App::$l10n->t('Something went FUBAR. ').$name.' != '.$element); } +/* preprocessing value */ switch($element) { case 'BDAY': $date = New DateTime($value); //$vcard->setDateTime('BDAY', $date, Sabre_VObject_Element_DateTime::DATE); $value = $date->format(DateTime::ATOM); + break; case 'FN': if(!$value) { // create a method thats returns an alternative for FN. //$value = getOtherValue(); } + break; + case 'CATEGORIES': + /* multi autocomplete triggers an save with empty value */ + if (!$value) { + $value = $vcard->getAsString('CATEGORIES'); + } + break; + case 'EMAIL': + $value = strtolower($value); + break; +} + +/* setting value */ +switch($element) { + case 'BDAY': + case 'FN': case 'N': case 'ORG': case 'NOTE': @@ -102,7 +120,6 @@ switch($element) { $vcard->setString($name, $value); break; case 'EMAIL': - $value = strtolower($value); case 'TEL': case 'ADR': // should I delete the property if empty or throw an error? debug('Setting element: (EMAIL/TEL/ADR)'.$element); diff --git a/apps/contacts/templates/part.contact.php b/apps/contacts/templates/part.contact.php index cb1e080a40..a1acb20b9c 100644 --- a/apps/contacts/templates/part.contact.php +++ b/apps/contacts/templates/part.contact.php @@ -64,7 +64,7 @@ $id = isset($_['id']) ? $_['id'] : ''; - +
      @@ -100,7 +100,7 @@ $id = isset($_['id']) ? $_['id'] : ''; - + @@ -112,7 +112,7 @@ $id = isset($_['id']) ? $_['id'] : ''; From 60a939dfcfceddbe1563e1712044a4a625bc70ac Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Mon, 26 Mar 2012 22:26:06 +0200 Subject: [PATCH 118/132] Small change and muting debug. --- apps/contacts/ajax/saveproperty.php | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/apps/contacts/ajax/saveproperty.php b/apps/contacts/ajax/saveproperty.php index 112d9031ce..924d873652 100644 --- a/apps/contacts/ajax/saveproperty.php +++ b/apps/contacts/ajax/saveproperty.php @@ -35,9 +35,9 @@ function bailOut($msg) { function debug($msg) { OC_Log::write('contacts','ajax/saveproperty.php: '.$msg, OC_Log::DEBUG); } -foreach ($_POST as $key=>$element) { - debug('_POST: '.$key.'=>'.print_r($element, true)); -} +// foreach ($_POST as $key=>$element) { +// debug('_POST: '.$key.'=>'.print_r($element, true)); +// } $id = isset($_POST['id'])?$_POST['id']:null; $name = isset($_POST['name'])?$_POST['name']:null; @@ -71,11 +71,6 @@ if(is_array($value)){ } else { $value = trim(strip_tags($value)); } -if(!$value) { - bailOut(OC_Contacts_App::$l10n->t('Cannot save empty value.')); -} - -debug('Element: '.$name.', value: '.print_r($value, true)); $vcard = OC_Contacts_App::getContactVCard( $id ); $line = OC_Contacts_App::getPropertyLineByChecksum($vcard, $checksum); @@ -112,6 +107,10 @@ switch($element) { break; } +if(!$value) { + bailOut(OC_Contacts_App::$l10n->t('Cannot save empty value.')); +} + /* setting value */ switch($element) { case 'BDAY': From 0c19e44a61229fe1376c8436b8a73e974b424539 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Mon, 26 Mar 2012 22:28:40 +0200 Subject: [PATCH 119/132] some more memory cleanup in OC_Image --- lib/image.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/lib/image.php b/lib/image.php index 60a714880d..62f35b4fc9 100644 --- a/lib/image.php +++ b/lib/image.php @@ -526,6 +526,7 @@ class OC_Image { imagedestroy($process); return false; } + imagedestroy($this->resource); $this->resource = $process; return true; } @@ -558,7 +559,14 @@ class OC_Image { imagedestroy($process); return false; } + imagedestroy($this->resource); $this->resource = $process; return true; } + + public function __destruct(){ + if(is_resource($this->resource)){ + imagedestroy($this->resource); + } + } } From 0ba93323585cd277d845eb7d7600cd4cac4f84da Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Mon, 26 Mar 2012 22:33:37 +0200 Subject: [PATCH 120/132] some more memory cleanup in OC_Image --- lib/image.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/image.php b/lib/image.php index 62f35b4fc9..4717f81af7 100644 --- a/lib/image.php +++ b/lib/image.php @@ -317,10 +317,7 @@ class OC_Image { */ public function loadFromFileHandle($handle) { OC_Log::write('core',__METHOD__.'(): Trying', OC_Log::DEBUG); - $contents = ''; - while (!feof($handle)) { - $contents .= fread($handle, 8192); - } + $contents = stream_get_contents($handle); if($this->loadFromData($contents)) { return $this->resource; } @@ -486,6 +483,7 @@ class OC_Image { imagedestroy($process); return false; } + imagedestroy($this->resource); $this->resource = $process; return true; } From 3f881f1ca50b50bb1d564c6bdf55789cda10d4d4 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Mon, 26 Mar 2012 22:40:38 +0200 Subject: [PATCH 121/132] memory cleanup in gallery --- apps/gallery/lib/photo.php | 6 +++--- apps/gallery/lib/scanner.php | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/apps/gallery/lib/photo.php b/apps/gallery/lib/photo.php index 0c0f16e659..2263608dcc 100644 --- a/apps/gallery/lib/photo.php +++ b/apps/gallery/lib/photo.php @@ -66,9 +66,9 @@ class OC_Gallery_Photo { $stmt->execute(array($newpath, $newAlbumId, $oldAlbumId, $oldpath)); } - public static function getThumbnail($image_name, $owner = null) { - if (!$owner) $owner = OC_User::getUser(); - $save_dir = OC_Config::getValue("datadirectory").'/'. $owner .'/gallery/'; + public static function getThumbnail($image_name, $owner = null) { + if (!$owner) $owner = OC_User::getUser(); + $save_dir = OC_Config::getValue("datadirectory").'/'. $owner .'/gallery/'; $save_dir .= dirname($image_name). '/'; $image_path = $image_name; $thumb_file = $save_dir . basename($image_name); diff --git a/apps/gallery/lib/scanner.php b/apps/gallery/lib/scanner.php index c8825c267e..34b9bb8da3 100644 --- a/apps/gallery/lib/scanner.php +++ b/apps/gallery/lib/scanner.php @@ -81,6 +81,7 @@ class OC_Gallery_Scanner { } } imagepng($thumbnail, OC_Config::getValue("datadirectory").'/'. OC_User::getUser() .'/gallery/' . $albumName.'.png'); + imagedestroy($thumbnail); } public static function createIntermediateAlbums() { From 73c6db5c8e6d876adf7b6c1c91049c66be26ba87 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Mon, 26 Mar 2012 23:53:48 +0200 Subject: [PATCH 122/132] crop and resize in a single step when creating thumbnail also so more explicit memory cleanup --- apps/gallery/lib/photo.php | 11 ++++++----- apps/gallery/lib/scanner.php | 1 + lib/image.php | 26 ++++++++++++++++++++------ 3 files changed, 27 insertions(+), 11 deletions(-) diff --git a/apps/gallery/lib/photo.php b/apps/gallery/lib/photo.php index 2263608dcc..3bb6f9129f 100644 --- a/apps/gallery/lib/photo.php +++ b/apps/gallery/lib/photo.php @@ -72,6 +72,9 @@ class OC_Gallery_Photo { $save_dir .= dirname($image_name). '/'; $image_path = $image_name; $thumb_file = $save_dir . basename($image_name); + if (!is_dir($save_dir)) { + mkdir($save_dir, 0777, true); + } if (file_exists($thumb_file)) { $image = new OC_Image($thumb_file); } else { @@ -81,17 +84,15 @@ class OC_Gallery_Photo { } $image = new OC_Image($image_path); if ($image->valid()) { - $image->centerCrop(); - $image->resize(200); + $image->centerCrop(200); $image->fixOrientation(); - if (!is_dir($save_dir)) { - mkdir($save_dir, 0777, true); - } $image->save($thumb_file); } } if ($image->valid()) { return $image; + }else{ + $image->destroy(); } return null; } diff --git a/apps/gallery/lib/scanner.php b/apps/gallery/lib/scanner.php index 34b9bb8da3..6d2d44d428 100644 --- a/apps/gallery/lib/scanner.php +++ b/apps/gallery/lib/scanner.php @@ -79,6 +79,7 @@ class OC_Gallery_Scanner { if ($image && $image->valid()) { imagecopyresampled($thumbnail, $image->resource(), $i*200, 0, 0, 0, 200, 200, 200, 200); } + $image->destroy(); } imagepng($thumbnail, OC_Config::getValue("datadirectory").'/'. OC_User::getUser() .'/gallery/' . $albumName.'.png'); imagedestroy($thumbnail); diff --git a/lib/image.php b/lib/image.php index 4717f81af7..b3c7d52ec2 100644 --- a/lib/image.php +++ b/lib/image.php @@ -216,7 +216,7 @@ class OC_Image { OC_Log::write('core','OC_Image->fixOrientation() No readable file path set.', OC_Log::DEBUG); return false; } - $exif = @exif_read_data($this->filepath, 'IFD0'); + $exif = @exif_read_data($this->filepath, 'IFD0'); if(!$exif) { return false; } @@ -267,6 +267,7 @@ class OC_Image { if($res) { if(imagealphablending($res, true)) { if(imagesavealpha($res, true)) { + imagedestroy($this->resource); $this->resource = $res; return true; } else { @@ -490,9 +491,10 @@ class OC_Image { /** * @brief Crops the image to the middle square. If the image is already square it just returns. + * @param int maximum size for the result (optional) * @returns bool for success or failure */ - public function centerCrop() { + public function centerCrop($size=0) { if(!$this->valid()) { OC_Log::write('core','OC_Image->centerCrop, No image loaded', OC_Log::ERROR); return false; @@ -512,13 +514,20 @@ class OC_Image { $y = ($height_orig/2) - ($height/2); $x = 0; } - $process = imagecreatetruecolor($width, $height); + if($size>0){ + $targetWidth=$size; + $targetHeight=$size; + }else{ + $targetWidth=$width; + $targetHeight=$height; + } + $process = imagecreatetruecolor($targetWidth, $targetHeight); if ($process == false) { OC_Log::write('core','OC_Image->centerCrop. Error creating true color image',OC_Log::ERROR); imagedestroy($process); return false; } - imagecopyresampled($process, $this->resource, 0, 0, $x, $y, $width, $height, $width, $height); + imagecopyresampled($process, $this->resource, 0, 0, $x, $y, $targetWidth, $targetHeight, $width, $height); if ($process == false) { OC_Log::write('core','OC_Image->centerCrop. Error resampling process image '.$width.'x'.$height,OC_Log::ERROR); imagedestroy($process); @@ -562,9 +571,14 @@ class OC_Image { return true; } - public function __destruct(){ - if(is_resource($this->resource)){ + public function destroy(){ + if($this->valid()){ imagedestroy($this->resource); } + $this->resource=null; + } + + public function __destruct(){ + $this->destroy(); } } From eb3ec05f882ec54cc19009966e62feb31f5577a4 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Mon, 26 Mar 2012 23:56:07 +0200 Subject: [PATCH 123/132] fix gallery scan when an image cant be loaded --- apps/gallery/lib/scanner.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/gallery/lib/scanner.php b/apps/gallery/lib/scanner.php index 6d2d44d428..0317f943e5 100644 --- a/apps/gallery/lib/scanner.php +++ b/apps/gallery/lib/scanner.php @@ -78,8 +78,8 @@ class OC_Gallery_Scanner { $image = OC_Gallery_Photo::getThumbnail($files[$i]); if ($image && $image->valid()) { imagecopyresampled($thumbnail, $image->resource(), $i*200, 0, 0, 0, 200, 200, 200, 200); + $image->destroy(); } - $image->destroy(); } imagepng($thumbnail, OC_Config::getValue("datadirectory").'/'. OC_User::getUser() .'/gallery/' . $albumName.'.png'); imagedestroy($thumbnail); From 128d446f39de93ce63bda3b8ef261446ad6efb0b Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Tue, 27 Mar 2012 00:21:31 +0200 Subject: [PATCH 124/132] fix timestamps when viewing logs --- settings/js/log.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/settings/js/log.js b/settings/js/log.js index 3814d9c10b..ae83f0a628 100644 --- a/settings/js/log.js +++ b/settings/js/log.js @@ -32,7 +32,7 @@ OC.Log={ row.append(messageTd); var timeTd=$(''); - timeTd.text(formatDate(entry.time)); + timeTd.text(formatDate(entry.time*1000)); row.append(timeTd); $('#log').append(row); } From 266699ddf90a074aa4c4f5b50a63f5f430842bde Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Tue, 27 Mar 2012 00:42:15 +0200 Subject: [PATCH 125/132] fix square images not getting proper thumbnails --- lib/image.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/image.php b/lib/image.php index b3c7d52ec2..4c53dc32f5 100644 --- a/lib/image.php +++ b/lib/image.php @@ -501,7 +501,7 @@ class OC_Image { } $width_orig=imageSX($this->resource); $height_orig=imageSY($this->resource); - if($width_orig === $height_orig) { + if($width_orig === $height_orig and $size==0) { return true; } $ratio_orig = $width_orig/$height_orig; From bcef775d6bc93144316d4eea74f90c5be03576b0 Mon Sep 17 00:00:00 2001 From: Arthur Schiwon Date: Tue, 27 Mar 2012 01:18:38 +0200 Subject: [PATCH 126/132] Overwrite Download-ZIP if it already exists. We do not want to show alien content. --- lib/files.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/files.php b/lib/files.php index 57ebb9005a..f1cf7573ba 100644 --- a/lib/files.php +++ b/lib/files.php @@ -64,7 +64,7 @@ class OC_Files { set_time_limit(0); $zip = new ZipArchive(); $filename = get_temp_dir()."/ownCloud.zip"; - if ($zip->open($filename, ZIPARCHIVE::CREATE)!==TRUE) { + if ($zip->open($filename, ZIPARCHIVE::CREATE | ZIPARCHIVE::OVERWRITE)!==TRUE) { exit("cannot open <$filename>\n"); } foreach($files as $file){ @@ -85,7 +85,7 @@ class OC_Files { set_time_limit(0); $zip = new ZipArchive(); $filename = get_temp_dir()."/ownCloud.zip"; - if ($zip->open($filename, ZIPARCHIVE::CREATE)!==TRUE) { + if ($zip->open($filename, ZIPARCHIVE::CREATE | ZIPARCHIVE::OVERWRITE)!==TRUE) { exit("cannot open <$filename>\n"); } $file=$dir.'/'.$files; From 24bc639222b3f4344bed388ca7fd834f8e70dff8 Mon Sep 17 00:00:00 2001 From: Arthur Schiwon Date: Tue, 27 Mar 2012 01:19:34 +0200 Subject: [PATCH 127/132] Do not use always the same name for download-zip to avoid collisions. --- lib/files.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/files.php b/lib/files.php index f1cf7573ba..e7bfbbc19b 100644 --- a/lib/files.php +++ b/lib/files.php @@ -63,7 +63,7 @@ class OC_Files { $executionTime = intval(ini_get('max_execution_time')); set_time_limit(0); $zip = new ZipArchive(); - $filename = get_temp_dir()."/ownCloud.zip"; + $filename = get_temp_dir().'/ownCloud_'.mt_rand(10000,99999).'.zip'; if ($zip->open($filename, ZIPARCHIVE::CREATE | ZIPARCHIVE::OVERWRITE)!==TRUE) { exit("cannot open <$filename>\n"); } @@ -84,7 +84,7 @@ class OC_Files { $executionTime = intval(ini_get('max_execution_time')); set_time_limit(0); $zip = new ZipArchive(); - $filename = get_temp_dir()."/ownCloud.zip"; + $filename = get_temp_dir().'/ownCloud_'.mt_rand(10000,99999).'.zip'; if ($zip->open($filename, ZIPARCHIVE::CREATE | ZIPARCHIVE::OVERWRITE)!==TRUE) { exit("cannot open <$filename>\n"); } From c92fc9bf651e79aa44803eeeed1d16499a5f08e6 Mon Sep 17 00:00:00 2001 From: Arthur Schiwon Date: Tue, 27 Mar 2012 02:24:52 +0200 Subject: [PATCH 128/132] return path of tmp file like filestorage/common does. Fixes broken folder-/multifile-download. --- lib/filesystemview.php | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/filesystemview.php b/lib/filesystemview.php index 89e0385fe9..39e47975b2 100644 --- a/lib/filesystemview.php +++ b/lib/filesystemview.php @@ -23,11 +23,11 @@ class OC_FilesystemView { private $fakeRoot=''; - + public function __construct($root){ $this->fakeRoot=$root; } - + public function getAbsolutePath($path){ if(!$path){ $path='/'; @@ -141,7 +141,7 @@ class OC_FilesystemView { while (!feof($handle)) { echo fread($handle, $chunkSize); @ob_flush(); - flush(); + flush(); } return $this->filesize($path); } @@ -282,7 +282,8 @@ class OC_FilesystemView { if($source){ $extention=substr($path,strrpos($path,'.')); $tmpFile=OC_Helper::tmpFile($extention); - return file_put_contents($tmpFile,$source); + file_put_contents($tmpFile,$source); + return $tmpFile; } } } From 0a07e5fdaabfc5652ec96b4179e2c9433ab42002 Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Tue, 27 Mar 2012 01:09:28 +0200 Subject: [PATCH 129/132] Added some documentation. --- core/js/oc-vcategories.txt | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/core/js/oc-vcategories.txt b/core/js/oc-vcategories.txt index 76d4245f5e..31216f80bd 100644 --- a/core/js/oc-vcategories.txt +++ b/core/js/oc-vcategories.txt @@ -17,7 +17,7 @@ Set the app specific values in your javascript file. This is what I've used for OCCategories.app = 'contacts'; OCCategories.changed = Contacts.UI.Card.categoriesChanged; -If OCCategories.changed point is set that function will be called each time the categories have been changed +If OCCategories.changed is set that function will be called each time the categories have been changed in the editor (add/delete/rescan) to allow the app to update the UI accordingly. The only argument to the function is an array of the updated categories e.g.: @@ -25,4 +25,9 @@ OCCategories.changed = function(categories) { for(var category in categories) { console.log(categories[category]); } -} \ No newline at end of file +} + +To show the categories editor call: + + OCCategories.edit() + From ff038f8766d49b2a4913ef5ae0a206758f2cdaaa Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Tue, 27 Mar 2012 10:12:30 +0200 Subject: [PATCH 130/132] Contacts: Update contact list thumbnail when deleting PHOTO. --- apps/contacts/js/contacts.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/apps/contacts/js/contacts.js b/apps/contacts/js/contacts.js index 18214cb1cc..82aadb54b8 100644 --- a/apps/contacts/js/contacts.js +++ b/apps/contacts/js/contacts.js @@ -667,6 +667,10 @@ Contacts={ console.log('NOTE or PHOTO'); Contacts.UI.propertyContainerFor(obj).hide(); Contacts.UI.propertyContainerFor(obj).data('checksum', ''); + if(proptype == 'PHOTO') { + console.log('Delete PHOTO'); + Contacts.UI.Contacts.refreshThumbnail(Contacts.UI.Card.id); + } } else { $('dl dt[data-element="'+proptype+'"],dd[data-element="'+proptype+'"]').hide(); $('dl dd[data-element="'+proptype+'"]').data('checksum', ''); @@ -990,7 +994,7 @@ Contacts={ OC.dialogs.alert(response.data.message, t('contacts', 'Error')); } }); - $('#contacts [data-id="'+this.id+'"]').find('a').css('background','url(thumbnail.php?id='+this.id+'&refresh=1'+Math.random()+') no-repeat'); + Contacts.UI.Contacts.refreshThumbnail(this.id); }, addMail:function() { //alert('addMail'); @@ -1192,6 +1196,9 @@ Contacts={ $(this).find('a').css('background','url(thumbnail.php?id='+$(this).data('id')+') no-repeat'); } }); + }, + refreshThumbnail:function(id){ + $('#contacts [data-id="'+id+'"]').find('a').css('background','url(thumbnail.php?id='+id+'&refresh=1'+Math.random()+') no-repeat'); } } } From fa165498ccfe2becbdaf997b4e36336e794cce50 Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Tue, 27 Mar 2012 12:26:59 +0200 Subject: [PATCH 131/132] Improvements in adding/deleting properties. --- apps/contacts/js/contacts.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/apps/contacts/js/contacts.js b/apps/contacts/js/contacts.js index 82aadb54b8..e182702745 100644 --- a/apps/contacts/js/contacts.js +++ b/apps/contacts/js/contacts.js @@ -613,10 +613,12 @@ Contacts={ this.loadPhoto(true); $('#file_upload_form').show(); $('#contacts_propertymenu a[data-type="'+type+'"]').parent().hide(); + $('#file_upload_start').trigger('click'); break; case 'NOTE': $('#note').show(); $('#contacts_propertymenu a[data-type="'+type+'"]').parent().hide(); + $('#note').find('textarea').focus(); break; case 'EMAIL': if($('#emaillist>li').length == 1) { @@ -644,6 +646,7 @@ Contacts={ case 'BDAY': case 'CATEGORIES': $('dl dt[data-element="'+type+'"],dd[data-element="'+type+'"]').show(); + $('dd[data-element="'+type+'"]').find('input').focus(); $('#contacts_propertymenu a[data-type="'+type+'"]').parent().hide(); break; } @@ -670,10 +673,13 @@ Contacts={ if(proptype == 'PHOTO') { console.log('Delete PHOTO'); Contacts.UI.Contacts.refreshThumbnail(Contacts.UI.Card.id); + } else if(proptype == 'NOTE') { + $('#note').find('textarea').val(''); } } else { $('dl dt[data-element="'+proptype+'"],dd[data-element="'+proptype+'"]').hide(); $('dl dd[data-element="'+proptype+'"]').data('checksum', ''); + $('dl dd[data-element="'+proptype+'"]').find('input').val(''); } $('#contacts_propertymenu a[data-type="'+proptype+'"]').parent().show(); Contacts.UI.loading(obj, false); From cb2dd97509ffd039fbd321aea4a8d631e3effcc7 Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Tue, 27 Mar 2012 12:29:19 +0200 Subject: [PATCH 132/132] Trigger autocomplete wo button. --- apps/contacts/js/jquery.multi-autocomplete.js | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/apps/contacts/js/jquery.multi-autocomplete.js b/apps/contacts/js/jquery.multi-autocomplete.js index 1c923a2543..7607de3f91 100644 --- a/apps/contacts/js/jquery.multi-autocomplete.js +++ b/apps/contacts/js/jquery.multi-autocomplete.js @@ -5,14 +5,25 @@ (function( $ ) { $.widget('ui.multiple_autocomplete', { _create: function() { + var self = this; function split( val ) { return val.split( /,\s*/ ); } function extractLast( term ) { return split( term ).pop(); } + function showOptions() { + if(!self.element.autocomplete('widget').is(':visible') && self.element.val().trim() == '') { + self.element.autocomplete('search', ''); + } + } //console.log('_create: ' + this.options['id']); - var self = this; + this.element.bind('click', function( event ) { + showOptions(); + }); + this.element.bind('input', function( event ) { + showOptions(); + }); this.element.bind('blur', function( event ) { var tmp = self.element.val().trim(); if(tmp[tmp.length-1] == ',') {