diff --git a/3rdparty/Dropbox/API.php b/3rdparty/Dropbox/API.php index cff6c35c7fbbda510e92baa205dcd3d317f782b6..8cdce678e1c8101d756cd72d36f4d9fbb49c18df 100644 --- a/3rdparty/Dropbox/API.php +++ b/3rdparty/Dropbox/API.php @@ -139,7 +139,7 @@ class Dropbox_API { public function copy($from, $to, $root = null) { if (is_null($root)) $root = $this->root; - $response = $this->oauth->fetch($this->api_url . 'fileops/copy', array('from_path' => $from, 'to_path' => $to, 'root' => $root)); + $response = $this->oauth->fetch($this->api_url . 'fileops/copy', array('from_path' => $from, 'to_path' => $to, 'root' => $root), 'POST'); return json_decode($response['body'],true); @@ -178,7 +178,7 @@ class Dropbox_API { public function delete($path, $root = null) { if (is_null($root)) $root = $this->root; - $response = $this->oauth->fetch($this->api_url . 'fileops/delete', array('path' => $path, 'root' => $root)); + $response = $this->oauth->fetch($this->api_url . 'fileops/delete', array('path' => $path, 'root' => $root), 'POST'); return json_decode($response['body']); } @@ -196,7 +196,7 @@ class Dropbox_API { public function move($from, $to, $root = null) { if (is_null($root)) $root = $this->root; - $response = $this->oauth->fetch($this->api_url . 'fileops/move', array('from_path' => rawurldecode($from), 'to_path' => rawurldecode($to), 'root' => $root)); + $response = $this->oauth->fetch($this->api_url . 'fileops/move', array('from_path' => rawurldecode($from), 'to_path' => rawurldecode($to), 'root' => $root), 'POST'); return json_decode($response['body'],true); diff --git a/3rdparty/Sabre/DAV/Client.php b/3rdparty/Sabre/DAV/Client.php index a8320dd978260c46a94944133f2ddae65ea815e2..23bd7c0539410c2863790775963354d8432768ad 100644 --- a/3rdparty/Sabre/DAV/Client.php +++ b/3rdparty/Sabre/DAV/Client.php @@ -249,6 +249,7 @@ class Sabre_DAV_Client { // Automatically follow redirects CURLOPT_FOLLOWLOCATION => true, CURLOPT_MAXREDIRS => 5, + //CURLOPT_SSL_VERIFYPEER => false, ); switch ($method) { diff --git a/apps/bookmarks/appinfo/migrate.php b/apps/bookmarks/appinfo/migrate.php index e7e572f52dc881c89782b4883bf1e4cfc766370a..f1353f1887eb180db6d402761a378c8bc5317b7b 100644 --- a/apps/bookmarks/appinfo/migrate.php +++ b/apps/bookmarks/appinfo/migrate.php @@ -40,8 +40,8 @@ class OC_Migration_Provider_Bookmarks extends OC_Migration_Provider{ $idmap = array(); while( $row = $results->fetchRow() ){ // Import each bookmark, saving its id into the map - $query = OCP\DB::prepare( "INSERT INTO *PREFIX*bookmarks(url, title, user_id, public, added, lastmodified) VALUES (?, ?, ?, ?, ?, ?)" ); - $query->execute( array( $row['url'], $row['title'], $this->uid, $row['public'], $row['added'], $row['lastmodified'] ) ); + $bookmarkquery = OCP\DB::prepare( "INSERT INTO *PREFIX*bookmarks(url, title, user_id, public, added, lastmodified) VALUES (?, ?, ?, ?, ?, ?)" ); + $bookmarkquery->execute( array( $row['url'], $row['title'], $this->uid, $row['public'], $row['added'], $row['lastmodified'] ) ); // Map the id $idmap[$row['id']] = OCP\DB::insertid(); } @@ -51,8 +51,8 @@ class OC_Migration_Provider_Bookmarks extends OC_Migration_Provider{ $results = $query->execute( array( $oldid ) ); while( $row = $results->fetchRow() ){ // Import the tags for this bookmark, using the new bookmark id - $query = OCP\DB::prepare( "INSERT INTO *PREFIX*bookmarks_tags(bookmark_id, tag) VALUES (?, ?)" ); - $query->execute( array( $newid, $row['tag'] ) ); + $tagquery = OCP\DB::prepare( "INSERT INTO *PREFIX*bookmarks_tags(bookmark_id, tag) VALUES (?, ?)" ); + $tagquery->execute( array( $newid, $row['tag'] ) ); } } // All done! diff --git a/apps/calendar/appinfo/app.php b/apps/calendar/appinfo/app.php index f1f2a26d87d476205cf944935881757634038308..3c8cc76133e5976f9219dd53c0ea6993ff44f5e6 100644 --- a/apps/calendar/appinfo/app.php +++ b/apps/calendar/appinfo/app.php @@ -8,12 +8,18 @@ OC::$CLASSPATH['OC_Connector_Sabre_CalDAV'] = 'apps/calendar/lib/connector_sabre OC::$CLASSPATH['OC_Calendar_Repeat'] = 'apps/calendar/lib/repeat.php'; OC::$CLASSPATH['OC_Calendar_Share'] = 'apps/calendar/lib/share.php'; OC::$CLASSPATH['OC_Search_Provider_Calendar'] = 'apps/calendar/lib/search.php'; +OC::$CLASSPATH['OC_Calendar_Export'] = 'apps/calendar/lib/export.php'; +//General Hooks OCP\Util::connectHook('OC_User', 'post_deleteUser', 'OC_Calendar_Hooks', 'deleteUser'); +//Repeating Events Hooks OCP\Util::connectHook('OC_Calendar', 'addEvent', 'OC_Calendar_Repeat', 'generate'); OCP\Util::connectHook('OC_Calendar', 'editEvent', 'OC_Calendar_Repeat', 'update'); OCP\Util::connectHook('OC_Calendar', 'deleteEvent', 'OC_Calendar_Repeat', 'clean'); OCP\Util::connectHook('OC_Calendar', 'moveEvent', 'OC_Calendar_Repeat', 'update'); OCP\Util::connectHook('OC_Calendar', 'deleteCalendar', 'OC_Calendar_Repeat', 'cleanCalendar'); +//Sharing Hooks +OCP\Util::connectHook('OC_Calendar', 'deleteEvent', 'OC_Calendar_Share', 'post_eventdelete'); +OCP\Util::connectHook('OC_Calendar', 'deleteCalendar', 'OC_Calendar_Share', 'post_caldelete'); OCP\Util::addscript('calendar','loader'); OCP\Util::addscript("3rdparty", "chosen/chosen.jquery.min"); OCP\Util::addStyle("3rdparty", "chosen/chosen"); diff --git a/apps/calendar/export.php b/apps/calendar/export.php index 5780d191a57bd308c2aa7ac0344c67801aaa28d3..1374c49cc0d0d443ffd2c2fbdaa78b3ca65f6fc7 100644 --- a/apps/calendar/export.php +++ b/apps/calendar/export.php @@ -5,35 +5,26 @@ * later. * See the COPYING-README file. */ - - OCP\User::checkLoggedIn(); OCP\App::checkAppEnabled('calendar'); $cal = isset($_GET['calid']) ? $_GET['calid'] : NULL; $event = isset($_GET['eventid']) ? $_GET['eventid'] : NULL; -$nl = "\r\n"; if(isset($cal)){ $calendar = OC_Calendar_App::getCalendar($cal, true); if(!$calendar){ header('HTTP/1.0 404 Not Found'); exit; } - $calobjects = OC_Calendar_Object::all($cal); header('Content-Type: text/Calendar'); - header('Content-Disposition: inline; filename=' . $calendar['displayname'] . '.ics'); - foreach($calobjects as $calobject){ - echo $calobject['calendardata'] . $nl; - } + header('Content-Disposition: inline; filename=' . str_replace(' ', '-', $calendar['displayname']) . '.ics'); + echo OC_Calendar_Export::export($cal, OC_Calendar_Export::CALENDAR); }elseif(isset($event)){ $data = OC_Calendar_App::getEventObject($_GET['eventid'], true); if(!$data){ header('HTTP/1.0 404 Not Found'); exit; } - $calendarid = $data['calendarid']; - $calendar = OC_Calendar_App::getCalendar($calendarid); header('Content-Type: text/Calendar'); - header('Content-Disposition: inline; filename=' . $data['summary'] . '.ics'); - echo $data['calendardata']; -} -?> + header('Content-Disposition: inline; filename=' . str_replace(' ', '-', $data['summary']) . '.ics'); + echo OC_Calendar_Export::export($event, OC_Calendar_Export::EVENT); +} \ No newline at end of file diff --git a/apps/calendar/js/calendar.js b/apps/calendar/js/calendar.js index e17f88e38be0a76b47159694d36a625b0e8e446f..004b2386fb19ad6bfea21306cb0aebdf5d70a8e6 100644 --- a/apps/calendar/js/calendar.js +++ b/apps/calendar/js/calendar.js @@ -547,7 +547,7 @@ Calendar={ $('#share_user').live('change', function(){ if($('#sharewithuser_' + $('#share_user option:selected').text()).length == 0){ Calendar.UI.Share.share(Calendar.UI.Share.currentid, Calendar.UI.Share.idtype, $('#share_user option:selected').text(), 'user'); - var newitem = '<li id="sharewithuser_' + $('#share_user option:selected').text() +'"><input type="checkbox" width="12px" style="visibility:hidden;" title="' + $('#share_user option:selected').text() + '">' + $('#share_user option:selected').text() + '<img src="' + oc_webroot + '/core/img/actions/delete.svg" class="svg action" style="display:none;float:right;"></li>'; + var newitem = '<li id="sharewithuser_' + $('#share_user option:selected').text() +'"><input type="checkbox" width="12px" style="visibility:hidden;" title="' + $('#share_user option:selected').text() + '">' + $('#share_user option:selected').text() + '<img src="' + OC.imagePath('core', 'actions/delete.svg') + '" class="svg action" style="display:none;float:right;"></li>'; $('#sharewithuser_list').append(newitem); $('#sharewithuser_' + $('#share_user option:selected').text() + ' > img').click(function(){ $('#share_user option[value="' + $(this).parent().text() + '"]').removeAttr('disabled'); @@ -562,7 +562,7 @@ Calendar={ $('#share_group').live('change', function(){ if($('#sharewithgroup_' + $('#share_group option:selected').text()).length == 0){ Calendar.UI.Share.share(Calendar.UI.Share.currentid, Calendar.UI.Share.idtype, $('#share_group option:selected').text(), 'group'); - var newitem = '<li id="sharewithgroup_' + $('#share_group option:selected').text() +'"><input type="checkbox" width="12px" style="visibility:hidden;" title="' + $('#share_group option:selected').text() + '">' + $('#share_group option:selected').text() + '<img src="' + oc_webroot + '/core/img/actions/delete.svg" class="svg action" style="display:none;float:right;"></li>'; + var newitem = '<li id="sharewithgroup_' + $('#share_group option:selected').text() +'"><input type="checkbox" width="12px" style="visibility:hidden;" title="' + $('#share_group option:selected').text() + '">' + $('#share_group option:selected').text() + '<img src="' + OC.imagePath('core', 'actions/delete.svg') + '" class="svg action" style="display:none;float:right;"></li>'; $('#sharewithgroup_list').append(newitem); $('#sharewithgroup_' + $('#share_group option:selected').text() + ' > img').click(function(){ $('#share_group option[value="' + $(this).parent().text() + '"]').removeAttr('disabled'); @@ -870,7 +870,7 @@ $(document).ready(function(){ eventDrop: Calendar.UI.moveEvent, eventResize: Calendar.UI.resizeEvent, eventRender: function(event, element) { - element.find('.fc-event-title').html(element.find('.fc-event-title').html()); + element.find('.fc-event-title').html(element.find('.fc-event-title').text()); element.tipsy({ className: 'tipsy-event', opacity: 0.9, diff --git a/apps/calendar/js/loader.js b/apps/calendar/js/loader.js index 0fc5018e89c55b7b6b9833bb6aa4c8658fefae77..cef95afc3aa46d7aaf1c9e85e09a05f61eb06934 100644 --- a/apps/calendar/js/loader.js +++ b/apps/calendar/js/loader.js @@ -44,7 +44,7 @@ Calendar_Import={ $('#newcalendar').attr('readonly', 'readonly'); $('#calendar').attr('disabled', 'disabled'); var progresskey = $('#progresskey').val(); - $.post(OC.filePath('calendar', 'ajax/import', 'import.php') + '?progresskey='+progresskey, {method: String (method), calname: String (calname), path: String (path), file: String (filename), id: String (calid)}, function(data){ + $.post(OC.filePath('calendar', 'ajax/import', 'import.php'), {progresskey: progresskey, method: String (method), calname: String (calname), path: String (path), file: String (filename), id: String (calid)}, function(data){ if(data.status == 'success'){ $('#progressbar').progressbar('option', 'value', 100); $('#import_done').css('display', 'block'); diff --git a/apps/calendar/lib/app.php b/apps/calendar/lib/app.php index 344c89f36b0d6fa6853918b84237f2120b4a5f49..1a13f2958c0dd1fcf61bf23618d8af44c74f790c 100644 --- a/apps/calendar/lib/app.php +++ b/apps/calendar/lib/app.php @@ -13,22 +13,22 @@ OC_Calendar_App::$tz = OCP\Config::getUserValue(OCP\USER::getUser(), 'calendar', class OC_Calendar_App{ const CALENDAR = 'calendar'; const EVENT = 'event'; - /* + /** * @brief language object for calendar app */ public static $l10n; - /* + /** * @brief categories of the user */ protected static $categories = null; - /* + /** * @brief timezone of the user */ public static $tz; - /* + /** * @brief returns informations about a calendar * @param int $id - id of the calendar * @param bool $security - check access rights or not @@ -53,7 +53,7 @@ class OC_Calendar_App{ return $calendar; } - /* + /** * @brief returns informations about an event * @param int $id - id of the event * @param bool $security - check access rights or not @@ -79,7 +79,7 @@ class OC_Calendar_App{ return $event; } - /* + /** * @brief returns the parsed calendar data * @param int $id - id of the event * @param bool $security - check access rights or not @@ -97,7 +97,7 @@ class OC_Calendar_App{ return $vobject; } - /* + /** * @brief checks if an event was edited and dies if it was * @param (object) $vevent - vevent object of the event * @param (int) $lastmodified - time of last modification as unix timestamp @@ -112,7 +112,7 @@ class OC_Calendar_App{ return true; } - /* + /** * @brief returns the default categories of ownCloud * @return (array) $categories */ @@ -136,7 +136,7 @@ class OC_Calendar_App{ ); } - /* + /** * @brief returns the vcategories object of the user * @return (object) $vcategories */ @@ -147,7 +147,7 @@ class OC_Calendar_App{ return self::$categories; } - /* + /** * @brief returns the categories of the vcategories object * @return (array) $categories */ @@ -202,12 +202,16 @@ class OC_Calendar_App{ self::getVCategories()->loadFromVObject($object, true); } } - + + /** + * @brief returns the options for the repeat rule of an repeating event + * @return array - valid inputs for the repeat rule of an repeating event + */ public static function getRepeatOptions(){ return OC_Calendar_Object::getRepeatOptions(self::$l10n); } - /* + /** * @brief returns the options for the end of an repeating event * @return array - valid inputs for the end of an repeating events */ @@ -215,7 +219,7 @@ class OC_Calendar_App{ return OC_Calendar_Object::getEndOptions(self::$l10n); } - /* + /** * @brief returns the options for an monthly repeating event * @return array - valid inputs for monthly repeating events */ @@ -223,7 +227,7 @@ class OC_Calendar_App{ return OC_Calendar_Object::getMonthOptions(self::$l10n); } - /* + /** * @brief returns the options for an weekly repeating event * @return array - valid inputs for weekly repeating events */ @@ -231,7 +235,7 @@ class OC_Calendar_App{ return OC_Calendar_Object::getWeeklyOptions(self::$l10n); } - /* + /** * @brief returns the options for an yearly repeating event * @return array - valid inputs for yearly repeating events */ @@ -239,7 +243,7 @@ class OC_Calendar_App{ return OC_Calendar_Object::getYearOptions(self::$l10n); } - /* + /** * @brief returns the options for an yearly repeating event which occurs on specific days of the year * @return array - valid inputs for yearly repeating events */ @@ -247,7 +251,7 @@ class OC_Calendar_App{ return OC_Calendar_Object::getByYearDayOptions(); } - /* + /** * @brief returns the options for an yearly repeating event which occurs on specific month of the year * @return array - valid inputs for yearly repeating events */ @@ -255,7 +259,7 @@ class OC_Calendar_App{ return OC_Calendar_Object::getByMonthOptions(self::$l10n); } - /* + /** * @brief returns the options for an yearly repeating event which occurs on specific week numbers of the year * @return array - valid inputs for yearly repeating events */ @@ -263,7 +267,7 @@ class OC_Calendar_App{ return OC_Calendar_Object::getByWeekNoOptions(); } - /* + /** * @brief returns the options for an yearly or monthly repeating event which occurs on specific days of the month * @return array - valid inputs for yearly or monthly repeating events */ @@ -271,7 +275,7 @@ class OC_Calendar_App{ return OC_Calendar_Object::getByMonthDayOptions(); } - /* + /** * @brief returns the options for an monthly repeating event which occurs on specific weeks of the month * @return array - valid inputs for monthly repeating events */ @@ -279,7 +283,7 @@ class OC_Calendar_App{ return OC_Calendar_Object::getWeekofMonth(self::$l10n); } - /* + /** * @brief checks the access for a calendar / an event * @param (int) $id - id of the calendar / event * @param (string) $type - type of the id (calendar/event) @@ -320,7 +324,7 @@ class OC_Calendar_App{ } } - /* + /** * @brief analyses the parameter for calendar parameter and returns the objects * @param (string) $calendarid - calendarid * @param (int) $start - unixtimestamp of start @@ -360,7 +364,7 @@ class OC_Calendar_App{ return $events; } - /* + /** * @brief generates the output for an event which will be readable for our js * @param (mixed) $event - event object / array * @param (int) $start - DateTime object of start @@ -368,12 +372,14 @@ class OC_Calendar_App{ * @return (array) $output - readable output */ public static function generateEventOutput($event, $start, $end){ - if(isset($event['calendardata'])){ - $object = OC_VObject::parse($event['calendardata']); - $vevent = $object->VEVENT; - }else{ - $vevent = $event['vevent']; + if(!isset($event['calendardata']) && !isset($event['vevent'])){ + return false; + } + if(!isset($event['calendardata']) && isset($event['vevent'])){ + $event['calendardata'] = "BEGIN:VCALENDAR\nVERSION:2.0\nPRODID:ownCloud's Internal iCal System\n" . $event['vevent']->serialize() . "END:VCALENDAR"; } + $object = OC_VObject::parse($event['calendardata']); + $vevent = $object->VEVENT; $return = array(); $id = $event['id']; $allday = ($vevent->DTSTART->getDateType() == Sabre_VObject_Element_DateTime::DATE)?true:false; @@ -404,7 +410,7 @@ class OC_Calendar_App{ $return[] = array_merge($staticoutput, $dynamicoutput); } }else{ - if(OC_Calendar_Object::isrepeating($id)){ + if(OC_Calendar_Object::isrepeating($id) || $event['repeating'] == 1){ $object->expand($start, $end); } foreach($object->getComponents() as $singleevent){ @@ -412,7 +418,7 @@ class OC_Calendar_App{ continue; } $dynamicoutput = OC_Calendar_Object::generateStartEndDate($singleevent->DTSTART, OC_Calendar_Object::getDTEndFromVEvent($singleevent), $allday, self::$tz); - $return[] = array_merge($staticoutput, $dynamicoutput); + $return[] = array_merge($staticoutput, $dynamicoutput); } } return $return; diff --git a/apps/calendar/lib/calendar.php b/apps/calendar/lib/calendar.php index 1bfab5cd645caaaec6930c27cdcc82bdb1fa9c8c..128b55c48e95f7bb1f20556a1f8bce0e30e5b86e 100644 --- a/apps/calendar/lib/calendar.php +++ b/apps/calendar/lib/calendar.php @@ -5,24 +5,11 @@ * later. * See the COPYING-README file. */ -/* +/** * * The following SQL statement is just a help for developers and will not be * executed! * - * CREATE TABLE calendar_objects ( - * id INTEGER UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT, - * calendarid INTEGER UNSIGNED NOT NULL, - * objecttype VARCHAR(40) NOT NULL, - * startdate DATETIME, - * enddate DATETIME, - * repeating INT(1), - * summary VARCHAR(255), - * calendardata TEXT, - * uri VARCHAR(100), - * lastmodified INT(11) - * ); - * * CREATE TABLE calendar_calendars ( * id INTEGER UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT, * userid VARCHAR(255), @@ -35,6 +22,7 @@ * timezone TEXT, * components VARCHAR(20) * ); + * */ /** @@ -212,7 +200,20 @@ class OC_Calendar_Calendar{ return true; } - + + /** + * @brief merges two calendars + * @param integer $id1 + * @param integer $id2 + * @return boolean + */ + public static function mergeCalendar($id1, $id2){ + $stmt = OCP\DB::prepare('UPDATE *PREFIX*calendar_objects SET calendarid = ? WHERE calendarid = ?'); + $stmt->execute(array($id1, $id2)); + self::touchCalendar($id1); + self::deleteCalendar($id2); + } + /** * @brief Creates a URI for Calendar * @param string $name name of the calendar @@ -238,6 +239,11 @@ class OC_Calendar_Calendar{ list($prefix,$userid) = Sabre_DAV_URLUtil::splitPath($principaluri); return $userid; } + + /** + * @brief returns the possible color for calendars + * @return array + */ public static function getCalendarColorOptions(){ return array( '#ff0000', // "Red" @@ -251,6 +257,11 @@ class OC_Calendar_Calendar{ ); } + /** + * @brief generates the Event Source Info for our JS + * @param array $calendar calendar data + * @return array + */ public static function getEventSourceInfo($calendar){ return array( 'url' => OCP\Util::linkTo('calendar', 'ajax/events.php').'?calendar_id='.$calendar['id'], diff --git a/apps/calendar/lib/export.php b/apps/calendar/lib/export.php new file mode 100644 index 0000000000000000000000000000000000000000..8f26891f366cde9e4060be52496e84110eb6ebe5 --- /dev/null +++ b/apps/calendar/lib/export.php @@ -0,0 +1,94 @@ +<?php +/** + * Copyright (c) 2012 Georg Ehrke <ownclouddev@georgswebsite.de> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ +/** + * This class does export and converts all times to UTC + */ +class OC_Calendar_Export{ + /** + * @brief Use one of these constants as second parameter if you call OC_Calendar_Export::export() + */ + const CALENDAR = 'calendar'; + const EVENT = 'event'; + + /** + * @brief export a calendar or an event + * @param integer $id id of calendar / event + * @param string $type use OC_Calendar_Export constants + * @return string + */ + public static function export($id, $type){ + if($type == self::EVENT){ + $return = self::event($id); + }else{ + $return = self::calendar($id); + } + return self::fixLineBreaks($return); + } + + /** + * @brief exports a calendar and convert all times to UTC + * @param integer $id id of the calendar + * @return string + */ + private static function calendar($id){ + $events = OC_Calendar_Object::all($id); + $calendar = OC_Calendar_Calendar::find($id); + $return = "BEGIN:VCALENDAR\nVERSION:2.0\nPRODID:ownCloud Calendar " . OCP\App::getAppVersion('calendar') . "\nX-WR-CALNAME:" . $calendar['displayname'] . "\n"; + foreach($events as $event){ + $return .= self::generateEvent($event); + } + $return .= "END:VCALENDAR"; + return $return; + } + + /** + * @brief exports an event and convert all times to UTC + * @param integer $id id of the event + * @return string + */ + private static function event($id){ + $event = OC_Calendar_Object::find($id); + $return = "BEGIN:VCALENDAR\nVERSION:2.0\nPRODID:ownCloud Calendar " . OCP\App::getAppVersion('calendar') . "\nX-WR-CALNAME:" . $event['summary'] . "\n"; + $return .= self::generateEvent($event); + $return .= "END:VCALENDAR"; + return $return; + } + + /** + * @brief generates the VEVENT with UTC dates + * @param array $event + * @return string + */ + private static function generateEvent($event){ + $object = OC_VObject::parse($event['calendardata']); + $dtstart = $object->VEVENT->DTSTART; + $start_dt = $dtstart->getDateTime(); + $dtend = OC_Calendar_Object::getDTEndFromVEvent($object->VEVENT); + $end_dt = $dtend->getDateTime(); + if($dtstart->getDateType() !== Sabre_VObject_Element_DateTime::DATE){ + $start_dt->setTimezone(new DateTimeZone('UTC')); + $end_dt->setTimezone(new DateTimeZone('UTC')); + $object->VEVENT->setDateTime('DTSTART', $start_dt, Sabre_VObject_Property_DateTime::UTC); + $object->VEVENT->setDateTime('DTEND', $end_dt, Sabre_VObject_Property_DateTime::UTC); + } + return $object->VEVENT->serialize(); + } + + /** + * @brief fixes new line breaks + * (fixes problems with Apple iCal) + * @param string $string to fix + * @return string + */ + private static function fixLineBreaks($string){ + $string = str_replace("\r\n", "\n", $string); + $string = str_replace("\r", "\n", $string); + $string = str_replace("\n", "\r\n", $string); + return $string; + } +} diff --git a/apps/calendar/lib/object.php b/apps/calendar/lib/object.php index 0531a56fc5017dc417e546ac30fdd74ffa7d0025..140542bf4fb901ef44df5dad1a6d40c397d3054b 100644 --- a/apps/calendar/lib/object.php +++ b/apps/calendar/lib/object.php @@ -1,10 +1,31 @@ <?php /** * Copyright (c) 2011 Jakob Sack <mail@jakobsack.de> + * Copyright (c) 2012 Bart Visscher <bartv@thisnet.nl> + * Copyright (c) 2012 Georg Ehrke <ownclouddev at georgswebsite dot de> * This file is licensed under the Affero General Public License version 3 or * later. * See the COPYING-README file. */ + /** + * + * The following SQL statement is just a help for developers and will not be + * executed! + * + * CREATE TABLE calendar_objects ( + * id INTEGER UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT, + * calendarid INTEGER UNSIGNED NOT NULL, + * objecttype VARCHAR(40) NOT NULL, + * startdate DATETIME, + * enddate DATETIME, + * repeating INT(1), + * summary VARCHAR(255), + * calendardata TEXT, + * uri VARCHAR(100), + * lastmodified INT(11) + * ); + * + */ /** * This class manages our calendar objects @@ -311,7 +332,12 @@ class OC_Calendar_Object{ public static function getUTCforMDB($datetime){ return date('Y-m-d H:i', $datetime->format('U') - $datetime->getOffset()); } - + + /** + * @brief returns the DTEND of an $vevent object + * @param object $vevent vevent object + * @return object + */ public static function getDTEndFromVEvent($vevent){ if ($vevent->DTEND) { $dtend = $vevent->DTEND; @@ -336,9 +362,12 @@ class OC_Calendar_Object{ } return $dtend; } - - public static function getRepeatOptions($l10n) - { + + /** + * @brief returns the options for the repeat rule of an repeating event + * @return array - valid inputs for the repeat rule of an repeating event + */ + public static function getRepeatOptions($l10n){ return array( 'doesnotrepeat' => $l10n->t('Does not repeat'), 'daily' => $l10n->t('Daily'), @@ -349,26 +378,35 @@ class OC_Calendar_Object{ 'yearly' => $l10n->t('Yearly') ); } - - public static function getEndOptions($l10n) - { + + /** + * @brief returns the options for the end of an repeating event + * @return array - valid inputs for the end of an repeating events + */ + public static function getEndOptions($l10n){ return array( 'never' => $l10n->t('never'), 'count' => $l10n->t('by occurrences'), 'date' => $l10n->t('by date') ); } - - public static function getMonthOptions($l10n) - { + + /** + * @brief returns the options for an monthly repeating event + * @return array - valid inputs for monthly repeating events + */ + public static function getMonthOptions($l10n){ return array( 'monthday' => $l10n->t('by monthday'), 'weekday' => $l10n->t('by weekday') ); } - - public static function getWeeklyOptions($l10n) - { + + /** + * @brief returns the options for an weekly repeating event + * @return array - valid inputs for weekly repeating events + */ + public static function getWeeklyOptions($l10n){ return array( 'MO' => $l10n->t('Monday'), 'TU' => $l10n->t('Tuesday'), @@ -379,9 +417,12 @@ class OC_Calendar_Object{ 'SU' => $l10n->t('Sunday') ); } - - public static function getWeekofMonth($l10n) - { + + /** + * @brief returns the options for an monthly repeating event which occurs on specific weeks of the month + * @return array - valid inputs for monthly repeating events + */ + public static function getWeekofMonth($l10n){ return array( 'auto' => $l10n->t('events week of month'), '1' => $l10n->t('first'), @@ -392,7 +433,11 @@ class OC_Calendar_Object{ '-1' => $l10n->t('last') ); } - + + /** + * @brief returns the options for an yearly repeating event which occurs on specific days of the year + * @return array - valid inputs for yearly repeating events + */ public static function getByYearDayOptions(){ $return = array(); foreach(range(1,366) as $num){ @@ -400,7 +445,11 @@ class OC_Calendar_Object{ } return $return; } - + + /** + * @brief returns the options for an yearly or monthly repeating event which occurs on specific days of the month + * @return array - valid inputs for yearly or monthly repeating events + */ public static function getByMonthDayOptions(){ $return = array(); foreach(range(1,31) as $num){ @@ -408,7 +457,11 @@ class OC_Calendar_Object{ } return $return; } - + + /** + * @brief returns the options for an yearly repeating event which occurs on specific month of the year + * @return array - valid inputs for yearly repeating events + */ public static function getByMonthOptions($l10n){ return array( '1' => $l10n->t('January'), @@ -425,7 +478,11 @@ class OC_Calendar_Object{ '12' => $l10n->t('December') ); } - + + /** + * @brief returns the options for an yearly repeating event + * @return array - valid inputs for yearly repeating events + */ public static function getYearOptions($l10n){ return array( 'bydate' => $l10n->t('by events date'), @@ -434,13 +491,21 @@ class OC_Calendar_Object{ 'bydaymonth' => $l10n->t('by day and month') ); } - + + /** + * @brief returns the options for an yearly repeating event which occurs on specific week numbers of the year + * @return array - valid inputs for yearly repeating events + */ public static function getByWeekNoOptions(){ return range(1, 52); } - - public static function validateRequest($request) - { + + /** + * @brief validates a request + * @param array $request + * @return mixed (array / boolean) + */ + public static function validateRequest($request){ $errnum = 0; $errarr = array('title'=>'false', 'cal'=>'false', 'from'=>'false', 'fromtime'=>'false', 'to'=>'false', 'totime'=>'false', 'endbeforestart'=>'false'); if($request['title'] == ''){ @@ -587,17 +652,24 @@ class OC_Calendar_Object{ } return false; } - - protected static function checkTime($time) - { + + /** + * @brief validates time + * @param string $time + * @return boolean + */ + protected static function checkTime($time){ list($hours, $minutes) = explode(':', $time); return empty($time) || $hours < 0 || $hours > 24 || $minutes < 0 || $minutes > 60; } - - public static function createVCalendarFromRequest($request) - { + + /** + * @brief creates an VCalendar Object from the request data + * @param array $request + * @return object created $vcalendar + */ public static function createVCalendarFromRequest($request){ $vcalendar = new OC_VObject('VCALENDAR'); $vcalendar->add('PRODID', 'ownCloud Calendar'); $vcalendar->add('VERSION', '2.0'); @@ -610,9 +682,14 @@ class OC_Calendar_Object{ $vevent->setUID(); return self::updateVCalendarFromRequest($request, $vcalendar); } - - public static function updateVCalendarFromRequest($request, $vcalendar) - { + + /** + * @brief updates an VCalendar Object from the request data + * @param array $request + * @param object $vcalendar + * @return object updated $vcalendar + */ + public static function updateVCalendarFromRequest($request, $vcalendar){ $title = $request["title"]; $location = $request["location"]; $categories = $request["categories"]; @@ -792,29 +869,52 @@ class OC_Calendar_Object{ $vevent->setString('DESCRIPTION', $description); $vevent->setString('CATEGORIES', $categories); - /*if($repeat == "true"){ + /**if($repeat == "true"){ $vevent->RRULE = $repeat; }*/ return $vcalendar; } - + + /** + * @brief returns the owner of an object + * @param integer $id + * @return string + */ public static function getowner($id){ $event = self::find($id); $cal = OC_Calendar_Calendar::find($event['calendarid']); return $cal['userid']; } + /** + * @brief returns the calendarid of an object + * @param integer $id + * @return integer + */ public static function getCalendarid($id){ $event = self::find($id); return $event['calendarid']; } - + + /** + * @brief checks if an object is repeating + * @param integer $id + * @return boolean + */ public static function isrepeating($id){ $event = self::find($id); return ($event['repeating'] == 1)?true:false; } - + + /** + * @brief converts the start_dt and end_dt to a new timezone + * @param object $dtstart + * @param object $dtend + * @param boolean $allday + * @param string $tz + * @return array + */ public static function generateStartEndDate($dtstart, $dtend, $allday, $tz){ $start_dt = $dtstart->getDateTime(); $end_dt = $dtend->getDateTime(); diff --git a/apps/calendar/lib/repeat.php b/apps/calendar/lib/repeat.php index 204f96a5a2a538ee057abe5d6b46693f0619b02c..b9fbee8fe0a376563965551fed379773ed47125a 100644 --- a/apps/calendar/lib/repeat.php +++ b/apps/calendar/lib/repeat.php @@ -5,12 +5,12 @@ * later. * See the COPYING-README file. */ -/* +/** * This class manages the caching of repeating events * Events will be cached for the current year ± 5 years */ class OC_Calendar_Repeat{ - /* + /** * @brief returns the cache of an event * @param (int) $id - id of the event * @return (array) @@ -24,7 +24,7 @@ class OC_Calendar_Repeat{ } return $return; } - /* + /** * @brief returns the cache of an event in a specific peroid * @param (int) $id - id of the event * @param (DateTime) $from - start for period in UTC @@ -44,7 +44,7 @@ class OC_Calendar_Repeat{ } return $return; } - /* + /** * @brief returns the cache of all repeating events of a calendar * @param (int) $id - id of the calendar * @return (array) @@ -58,7 +58,7 @@ class OC_Calendar_Repeat{ } return $return; } - /* + /** * @brief returns the cache of all repeating events of a calendar in a specific period * @param (int) $id - id of the event * @param (string) $from - start for period in UTC @@ -78,7 +78,7 @@ class OC_Calendar_Repeat{ } return $return; } - /* + /** * @brief generates the cache the first time * @param (int) id - id of the event * @return (bool) @@ -104,7 +104,7 @@ class OC_Calendar_Repeat{ } return true; } - /* + /** * @brief generates the cache the first time for all repeating event of an calendar * @param (int) id - id of the calendar * @return (bool) @@ -116,7 +116,7 @@ class OC_Calendar_Repeat{ } return true; } - /* + /** * @brief updates an event that is already cached * @param (int) id - id of the event * @return (bool) @@ -126,7 +126,7 @@ class OC_Calendar_Repeat{ self::generate($id); return true; } - /* + /** * @brief updates all repating events of a calendar that are already cached * @param (int) id - id of the calendar * @return (bool) @@ -136,7 +136,7 @@ class OC_Calendar_Repeat{ self::generateCalendar($id); return true; } - /* + /** * @brief checks if an event is already cached * @param (int) id - id of the event * @return (bool) @@ -148,7 +148,7 @@ class OC_Calendar_Repeat{ return false; } } - /* + /** * @brief checks if an event is already cached in a specific period * @param (int) id - id of the event * @param (DateTime) $from - start for period in UTC @@ -163,7 +163,7 @@ class OC_Calendar_Repeat{ } } - /* + /** * @brief checks if a whole calendar is already cached * @param (int) id - id of the calendar * @return (bool) @@ -183,7 +183,7 @@ class OC_Calendar_Repeat{ return true; } } - /* + /** * @brief removes the cache of an event * @param (int) id - id of the event * @return (bool) @@ -192,7 +192,7 @@ class OC_Calendar_Repeat{ $stmt = OCP\DB::prepare('DELETE FROM *PREFIX*calendar_repeat WHERE eventid = ?'); $stmt->execute(array($id)); } - /* + /** * @brief removes the cache of all events of a calendar * @param (int) id - id of the calendar * @return (bool) diff --git a/apps/calendar/lib/share.php b/apps/calendar/lib/share.php index 54c531892f05b3c095b83022a6619fbab2fc91fb..4fe88171403c47624964a5e90b68852b6cea4731 100644 --- a/apps/calendar/lib/share.php +++ b/apps/calendar/lib/share.php @@ -5,17 +5,17 @@ * later. * See the COPYING-README file. */ -/* +/** * This class manages shared calendars */ class OC_Calendar_Share{ const CALENDAR = 'calendar'; const EVENT = 'event'; - /* + /** * @brief: returns informations about all calendar or events which users are sharing with the user - userid - * @param: (string) $userid - id of the user - * @param: (string) $type - use const self::CALENDAR or self::EVENT - * @return: (array) $return - information about calendars + * @param: string $userid - id of the user + * @param: string $type - use const self::CALENDAR or self::EVENT + * @return: array $return - information about calendars */ public static function allSharedwithuser($userid, $type, $active=null, $permission=null){ $group_where = self::group_sql(OC_Group::getUserGroups($userid)); @@ -33,11 +33,11 @@ class OC_Calendar_Share{ } return $return; } - /* + /** * @brief: returns all users a calendar / event is shared with - * @param: (int) id - id of the calendar / event - * @param: (string) $type - use const self::CALENDAR or self::EVENT - * @return: (array) $users - information about users a calendar / event is shared with + * @param: integer id - id of the calendar / event + * @param: string $type - use const self::CALENDAR or self::EVENT + * @return: array $users - information about users a calendar / event is shared with */ public static function allUsersSharedwith($id, $type){ $stmt = OCP\DB::prepare('SELECT * FROM *PREFIX*calendar_share_' . $type . ' WHERE ' . $type . 'id = ? ORDER BY share'); @@ -48,13 +48,13 @@ class OC_Calendar_Share{ } return $users; } - /* + /** * @brief: shares a calendar / event - * @param: (string) $owner - userid of the owner - * @param: (string) $share - userid (if $sharetype == user) / groupid (if $sharetype == group) / token (if $sharetype == public) - * @param: (string) $sharetype - type of sharing (can be: user/group/public) - * @param: (string) $id - id of the calendar / event - * @param: (string) $type - use const self::CALENDAR or self::EVENT + * @param: string $owner - userid of the owner + * @param: string $share - userid (if $sharetype == user) / groupid (if $sharetype == group) / token (if $sharetype == public) + * @param: string $sharetype - type of sharing (can be: user/group/public) + * @param: string $id - id of the calendar / event + * @param: string $type - use const self::CALENDAR or self::EVENT * @return (mixed) - token (if $sharetype == public) / bool (if $sharetype != public) */ public static function share($owner, $share, $sharetype, $id, $type){ @@ -80,14 +80,14 @@ class OC_Calendar_Share{ return true; } } - /* + /** * @brief: stops sharing a calendar / event - * @param: (string) $owner - userid of the owner - * @param: (string) $share - userid (if $sharetype == user) / groupid (if $sharetype == group) / token (if $sharetype == public) - * @param: (string) $sharetype - type of sharing (can be: user/group/public) - * @param: (string) $id - id of the calendar / event - * @param: (string) $type - use const self::CALENDAR or self::EVENT - * @return (bool) + * @param: string $owner - userid of the owner + * @param: string $share - userid (if $sharetype == user) / groupid (if $sharetype == group) / token (if $sharetype == public) + * @param: string $sharetype - type of sharing (can be: user/group/public) + * @param: string $id - id of the calendar / event + * @param: string $type - use const self::CALENDAR or self::EVENT + * @return boolean */ public static function unshare($owner, $share, $sharetype, $id, $type){ $stmt = OCP\DB::prepare('DELETE FROM *PREFIX*calendar_share_' . $type . ' WHERE owner = ? ' . (($sharetype != 'public')?'AND share = ?':'') . ' AND sharetype = ? AND ' . $type . 'id = ?'); @@ -98,14 +98,14 @@ class OC_Calendar_Share{ } return true; } - /* + /** * @brief: changes the permission for a calendar / event - * @param: (string) $share - userid (if $sharetype == user) / groupid (if $sharetype == group) / token (if $sharetype == public) - * @param: (string) $sharetype - type of sharing (can be: user/group/public) - * @param: (string) $id - id of the calendar / event - * @param: (int) $permission - permission of user the calendar / event is shared with (if $sharetype == public then $permission = 0) - * @param: (string) $type - use const self::CALENDAR or self::EVENT - * @return (bool) + * @param: string $share - userid (if $sharetype == user) / groupid (if $sharetype == group) / token (if $sharetype == public) + * @param: string $sharetype - type of sharing (can be: user/group/public) + * @param: string $id - id of the calendar / event + * @param: integer $permission - permission of user the calendar / event is shared with (if $sharetype == public then $permission = 0) + * @param: string $type - use const self::CALENDAR or self::EVENT + * @return boolean */ public static function changepermission($share, $sharetype, $id, $permission, $type){ if($sharetype == 'public' && $permission == 1){ @@ -115,9 +115,9 @@ class OC_Calendar_Share{ $stmt->execute(array($permission, $share, $sharetype, $id)); return true; } - /* + /** * @brief: generates a token for public calendars / events - * @return: (string) $token + * @return: string $token */ private static function generate_token($id, $type){ $uniqid = uniqid(); @@ -138,14 +138,14 @@ class OC_Calendar_Share{ $token = md5($string); return substr($token, rand(0,16), 15); } - /* + /** * @brief: checks if it is already shared - * @param: (string) $owner - userid of the owner - * @param: (string) $share - userid (if $sharetype == user) / groupid (if $sharetype == group) / token (if $sharetype == public) - * @param: (string) $sharetype - type of sharing (can be: user/group/public) - * @param: (string) $id - id of the calendar / event - * @param: (string) $type - use const self::CALENDAR or self::EVENT - * @return (bool) + * @param: string $owner - userid of the owner + * @param: string $share - userid (if $sharetype == user) / groupid (if $sharetype == group) / token (if $sharetype == public) + * @param: string $sharetype - type of sharing (can be: user/group/public) + * @param: string $id - id of the calendar / event + * @param: string $type - use const self::CALENDAR or self::EVENT + * @return boolean */ public static function is_already_shared($owner, $share, $sharetype, $id, $type){ $stmt = OCP\DB::prepare('SELECT * FROM *PREFIX*calendar_share_' . $type . ' WHERE owner = ? AND share = ? AND sharetype = ? AND ' . $type . 'id = ?'); @@ -181,12 +181,12 @@ class OC_Calendar_Share{ } return $active_where; } - /* + /** * @brief: checks the permission for editing an event - * @param: (string) $share - userid (if $sharetype == user) / groupid (if $sharetype == group) / token (if $sharetype == public) - * @param: (string) $id - id of the calendar / event - * @param: (string) $type - use const self::CALENDAR or self::EVENT - * @return (bool) + * @param: string $share - userid (if $sharetype == user) / groupid (if $sharetype == group) / token (if $sharetype == public) + * @param: string $id - id of the calendar / event + * @param: string $type - use const self::CALENDAR or self::EVENT + * @return boolean */ public static function is_editing_allowed($share, $id, $type){ $group_where = self::group_sql(OC_Group::getUserGroups($share)); @@ -202,12 +202,12 @@ class OC_Calendar_Share{ } return false; } - /* + /** * @brief: checks the access of - * @param: (string) $share - userid (if $sharetype == user) / groupid (if $sharetype == group) / token (if $sharetype == public) - * @param: (string) $id - id of the calendar / event - * @param: (string) $type - use const self::CALENDAR or self::EVENT - * @return (bool) + * @param: string $share - userid (if $sharetype == user) / groupid (if $sharetype == group) / token (if $sharetype == public) + * @param: string $id - id of the calendar / event + * @param: string $type - use const self::CALENDAR or self::EVENT + * @return boolean */ public static function check_access($share, $id, $type){ $group_where = self::group_sql(OC_Group::getUserGroups($share)); @@ -223,9 +223,9 @@ class OC_Calendar_Share{ return false; } } - /* + /** * @brief: returns the calendardata of an event or a calendar - * @param: (string) $token - token which should be searched + * @param: string $token - token which should be searched * @return: mixed - bool if false, array with type and id if true */ public static function getElementByToken($token){ @@ -248,19 +248,19 @@ class OC_Calendar_Share{ return $return; } - /* + /** * @brief sets the active status of the calendar - * @param (string) $ + * @param string */ public static function set_active($share, $id, $active){ $stmt = OCP\DB::prepare("UPDATE *PREFIX*calendar_share_calendar SET active = ? WHERE share = ? AND sharetype = 'user' AND calendarid = ?"); $stmt->execute(array($active, $share, $id)); } - /* - * @brief delete all shared calendars / events after a user was deleted - * @param (string) $userid - * @return (bool) + /** + * @brief deletes all shared calendars / events after a user was deleted + * @param string $userid + * @return boolean */ public static function post_userdelete($userid){ $stmt = OCP\DB::prepare('DELETE FROM *PREFIX*calendar_share_calendar WHERE owner = ?'); @@ -273,4 +273,26 @@ class OC_Calendar_Share{ $stmt->execute(array($userid)); return true; } + + /** + * @brief deletes all shared events of a calendar + * @param integer $calid + * @return boolean + */ + public static function post_caldelete($calid){ + $stmt = OCP\DB::prepare('DELETE FROM *PREFIX*calendar_share_calendar WHERE calendarid = ?'); + $stmt->execute(array($calid)); + return true; + } + + /** + * @brief deletes all shares of an event + * @param integer $eventid + * @return boolean + */ + public static function post_eventdelete($eventid){ + $stmt = OCP\DB::prepare('DELETE FROM *PREFIX*calendar_share_event WHERE eventid = ?'); + $stmt->execute(array($eventid)); + return true; + } } \ No newline at end of file diff --git a/apps/calendar/share.php b/apps/calendar/share.php index 68c7d0ffae28013b156ff2af4249bb3cfc7e67a9..bffcf0b47097d37beba707c32242538be6bf3d71 100644 --- a/apps/calendar/share.php +++ b/apps/calendar/share.php @@ -1,22 +1,31 @@ <?php +/** + * Copyright (c) 2012 Georg Ehrke <ownclouddev at georgswebsite dot de> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ $token = strip_tags($_GET['t']); $shared = OC_Calendar_Share::getElementByToken($token); -$nl = "\n\r"; if($shared['type'] == OC_Calendar_Share::CALENDAR){ $calendar = OC_Calendar_App::getCalendar($shared['id'], false); - $calobjects = OC_Calendar_Object::all($shared['id']); - header('Content-Type: text/Calendar'); - header('Content-Disposition: inline; filename=' . $calendar['displayname'] . '.ics'); - foreach($calobjects as $calobject){ - echo $calobject['calendardata'] . $nl; + if(!$calendar){ + header('HTTP/1.0 404 Not Found'); + exit; } + header('Content-Type: text/Calendar'); + header('Content-Disposition: inline; filename=' . str_replace(' ', '-', $calendar['displayname']) . '.ics'); + echo OC_Calendar_Export::export($shared['id'], OC_Calendar_Export::CALENDAR); }elseif($shared['type'] == OC_Calendar_Share::EVENT){ $data = OC_Calendar_App::getEventObject($shared['id'], false); - $calendarid = $data['calendarid']; - $calendar = OC_Calendar_App::getCalendar($calendarid); + if(!$data){ + header('HTTP/1.0 404 Not Found'); + exit; + } header('Content-Type: text/Calendar'); - header('Content-Disposition: inline; filename=' . $data['summary'] . '.ics'); - echo $data['calendardata']; + header('Content-Disposition: inline; filename=' . str_replace(' ', '-', $data['summary']) . '.ics'); + echo OC_Calendar_Export::export($shared['id'], OC_Calendar_Export::EVENT); }else{ - header('Error 404: Not Found'); -} \ No newline at end of file + header('HTTP/1.0 404 Not Found'); + exit; +} diff --git a/apps/contacts/ajax/contacts.php b/apps/contacts/ajax/contacts.php index 07b442159c91670482c4189e481d1c0193477c90..67ebcaf7362fc79cfcd0aac6081c3df077b72543 100644 --- a/apps/contacts/ajax/contacts.php +++ b/apps/contacts/ajax/contacts.php @@ -17,24 +17,44 @@ function cmp($a, $b) OCP\JSON::checkLoggedIn(); OCP\JSON::checkAppEnabled('contacts'); -$active_addressbooks = OC_Contacts_Addressbook::active(OCP\USER::getUser()); +$start = isset($_GET['startat'])?$_GET['startat']:0; +$aid = isset($_GET['aid'])?$_GET['aid']:null; +if(is_null($aid)) { + // Called initially to get the active addressbooks. + $active_addressbooks = OC_Contacts_Addressbook::active(OCP\USER::getUser()); +} else { + // called each time more contacts has to be shown. + $active_addressbooks = array(OC_Contacts_Addressbook::find($aid)); +} + + +session_write_close(); + +// create the addressbook associate array $contacts_addressbook = array(); $ids = array(); foreach($active_addressbooks as $addressbook) { $ids[] = $addressbook['id']; if(!isset($contacts_addressbook[$addressbook['id']])) { - $contacts_addressbook[$addressbook['id']] = array('contacts' => array()); + $contacts_addressbook[$addressbook['id']] = array('contacts' => array('type' => 'book',)); $contacts_addressbook[$addressbook['id']]['displayname'] = $addressbook['displayname']; } } -$contacts_alphabet = OC_Contacts_VCard::all($ids); +$contacts_alphabet = array(); + +// get next 50 for each addressbook. +foreach($ids as $id) { + if($id) { + $contacts_alphabet = array_merge($contacts_alphabet, OC_Contacts_VCard::all($id, $start, 50)); + } +} // Our new array for the contacts sorted by addressbook if($contacts_alphabet) { foreach($contacts_alphabet as $contact) { if(!isset($contacts_addressbook[$contact['addressbookid']])) { // It should never execute. - $contacts_addressbook[$contact['addressbookid']] = array('contacts' => array()); + $contacts_addressbook[$contact['addressbookid']] = array('contacts' => array('type' => 'book',)); } $display = trim($contact['fullname']); if(!$display) { @@ -44,15 +64,11 @@ if($contacts_alphabet) { $display = isset($struct['EMAIL'][0])?$struct['EMAIL'][0]['value']:'[UNKNOWN]'; } } - $contacts_addressbook[$contact['addressbookid']]['contacts'][] = array('id' => $contact['id'], 'addressbookid' => $contact['addressbookid'], 'displayname' => htmlspecialchars($display)); + $contacts_addressbook[$contact['addressbookid']]['contacts'][] = array('type' => 'contact', 'id' => $contact['id'], 'addressbookid' => $contact['addressbookid'], 'displayname' => htmlspecialchars($display)); } } unset($contacts_alphabet); uasort($contacts_addressbook, 'cmp'); -$tmpl = new OCP\Template("contacts", "part.contacts"); -$tmpl->assign('books', $contacts_addressbook, false); -$page = $tmpl->fetchPage(); - -OCP\JSON::success(array('data' => array( 'page' => $page ))); +OCP\JSON::success(array('data' => array('entries' => $contacts_addressbook))); diff --git a/apps/contacts/ajax/loadphoto.php b/apps/contacts/ajax/loadphoto.php index 61b5356edce31c3bb28b3cd6d43c990d85ef037a..a35631055eba7f82b657c49b13c761888f2d0eb1 100644 --- a/apps/contacts/ajax/loadphoto.php +++ b/apps/contacts/ajax/loadphoto.php @@ -42,11 +42,5 @@ foreach($vcard->children as $property){ } } -$tmpl = new OCP\Template("contacts", "part.contactphoto"); -$tmpl->assign('id', $id); -if($refresh) { - $tmpl->assign('refresh', 1); -} -$page = $tmpl->fetchPage(); -OCP\JSON::success(array('data' => array('page'=>$page, 'checksum'=>$checksum))); -?> +OCP\JSON::success(array('data' => array('checksum'=>$checksum))); + diff --git a/apps/contacts/ajax/uploadimport.php b/apps/contacts/ajax/uploadimport.php index c1e9c8b1ad15e7e4ae6fed34f2374f79d33d4bfa..9511520828f032e392faabcfc3517e27c2715cca 100644 --- a/apps/contacts/ajax/uploadimport.php +++ b/apps/contacts/ajax/uploadimport.php @@ -23,6 +23,7 @@ // Check if we are a user OCP\JSON::checkLoggedIn(); OCP\JSON::checkAppEnabled('contacts'); +OCP\JSON::callCheck(); require_once('loghandler.php'); $view = OCP\Files::getStorage('contacts'); diff --git a/apps/contacts/appinfo/database.xml b/apps/contacts/appinfo/database.xml index 7c8268d71f53430c61b45ab6a27d2e34df035a44..9b269d765dc2082ef64be1ada8509e777e13c869 100644 --- a/apps/contacts/appinfo/database.xml +++ b/apps/contacts/appinfo/database.xml @@ -62,6 +62,14 @@ <length>4</length> </field> + <field> + <name>active</name> + <type>integer</type> + <default>1</default> + <notnull>true</notnull> + <length>4</length> + </field> + </declaration> </table> diff --git a/apps/contacts/appinfo/migrate.php b/apps/contacts/appinfo/migrate.php index 1400cdf79d4707d4b76da70674b430ee1c8993aa..02026c5979cc439aed89c00dc51c0a47d1e8fafd 100644 --- a/apps/contacts/appinfo/migrate.php +++ b/apps/contacts/appinfo/migrate.php @@ -30,7 +30,7 @@ class OC_Migration_Provider_Contacts extends OC_Migration_Provider{ } - // Import function for bookmarks + // Import function for contacts function import( ){ switch( $this->appinfo->version ){ default: @@ -39,20 +39,23 @@ class OC_Migration_Provider_Contacts extends OC_Migration_Provider{ $results = $query->execute( array( $this->olduid ) ); $idmap = array(); while( $row = $results->fetchRow() ){ - // Import each bookmark, saving its id into the map - $query = OCP\DB::prepare( "INSERT INTO *PREFIX*contacts_addressbooks (`userid`, `displayname`, `uri`, `description`, `ctag`) VALUES (?, ?, ?, ?, ?)" ); - $query->execute( array( $this->uid, $row['displayname'], $row['uri'], $row['description'], $row['ctag'] ) ); + // Import each addressbook + $addressbookquery = OCP\DB::prepare( "INSERT INTO *PREFIX*contacts_addressbooks (`userid`, `displayname`, `uri`, `description`, `ctag`) VALUES (?, ?, ?, ?, ?)" ); + $addressbookquery->execute( array( $this->uid, $row['displayname'], $row['uri'], $row['description'], $row['ctag'] ) ); // Map the id - $idmap[$row['id']] = OCP\DB::insertid(); + $idmap[$row['id']] = OCP\DB::insertid('*PREFIX*contacts_addressbooks'); + // Make the addressbook active + OC_Contacts_Addressbook::setActive($idmap[$row['id']], true); } // Now tags foreach($idmap as $oldid => $newid){ + $query = $this->content->prepare( "SELECT * FROM contacts_cards WHERE addressbookid LIKE ?" ); $results = $query->execute( array( $oldid ) ); while( $row = $results->fetchRow() ){ - // Import the tags for this bookmark, using the new bookmark id - $query = OCP\DB::prepare( "INSERT INTO *PREFIX*contacts_cards (`addressbookid`, `fullname`, `carddata`, `uri`, `lastmodified`) VALUES (?, ?, ?, ?, ?)" ); - $query->execute( array( $newid, $row['fullname'], $row['carddata'], $row['uri'], $row['lastmodified'] ) ); + // Import the contacts + $contactquery = OCP\DB::prepare( "INSERT INTO *PREFIX*contacts_cards (`addressbookid`, `fullname`, `carddata`, `uri`, `lastmodified`) VALUES (?, ?, ?, ?, ?)" ); + $contactquery->execute( array( $newid, $row['fullname'], $row['carddata'], $row['uri'], $row['lastmodified'] ) ); } } // All done! diff --git a/apps/contacts/appinfo/update.php b/apps/contacts/appinfo/update.php new file mode 100644 index 0000000000000000000000000000000000000000..873899f578bcecc44a7851c07b85b9f99695c5a8 --- /dev/null +++ b/apps/contacts/appinfo/update.php @@ -0,0 +1,25 @@ +<?php + +$installedVersion=OCP\Config::getAppValue('contacts', 'installed_version'); +if (version_compare($installedVersion, '0.2.90', '<')) { + // First set all address books in-active. + $stmt = OCP\DB::prepare( 'UPDATE *PREFIX*contacts_addressbooks SET active=0' ); + $result = $stmt->execute(array()); + + // Then get all the active address books. + $stmt = OCP\DB::prepare( 'SELECT userid,configvalue FROM *PREFIX*preferences WHERE appid=\'contacts\' AND configkey=\'openaddressbooks\'' ); + $result = $stmt->execute(array()); + + // Prepare statement for updating the new 'active' field. + $stmt = OCP\DB::prepare( 'UPDATE *PREFIX*contacts_addressbooks SET active=? WHERE id=? AND userid=?' ); + while( $row = $result->fetchRow()) { + $ids = explode(';', $row['configvalue']); + foreach($ids as $id) { + $r = $stmt->execute(array(1, $id, $row['userid'])); + } + } + + // Remove the old preferences. + $stmt = OCP\DB::prepare( 'DELETE FROM *PREFIX*preferences WHERE appid=\'contacts\' AND configkey=\'openaddressbooks\'' ); + $result = $stmt->execute(array()); +} diff --git a/apps/contacts/appinfo/version b/apps/contacts/appinfo/version index 2f4536184bcac31936bd15a5f9cf931dd526c022..7dff5b8921122a487162febe3c8e32effb7acb35 100644 --- a/apps/contacts/appinfo/version +++ b/apps/contacts/appinfo/version @@ -1 +1 @@ -0.2 \ No newline at end of file +0.2.1 \ No newline at end of file diff --git a/apps/contacts/css/contacts.css b/apps/contacts/css/contacts.css index 1766c28761ec03e270afc03ec32e479a85b786bd..5b6ccb7638a681846f55b8edc79e2906297231bc 100644 --- a/apps/contacts/css/contacts.css +++ b/apps/contacts/css/contacts.css @@ -12,12 +12,13 @@ .ui-draggable-dragging { width: 16em; } .ui-state-hover { border: 1px solid dashed; } #bottomcontrols { padding: 0; bottom:0px; height:2.8em; width: 20em; margin:0; background:#eee; border-top:1px solid #ccc; position:fixed; -moz-box-shadow: 0 -3px 3px -3px #000; -webkit-box-shadow: 0 -3px 3px -3px #000; box-shadow: 0 -3px 3px -3px #000;} +#bottomcontrols img { margin-top: 0.35em; } #contacts_newcontact { float: left; margin: 0.2em 0 0 1em; } #chooseaddressbook { float: right; margin: 0.2em 1em 0 0; } -#actionbar { height: 30px; width: 60px; position: fixed; right: 0px; top: 4em; margin: 0 0 0 0; padding: 0 0 0 0; z-index: 1000; } +#actionbar { position: relative; clear: both; height: 30px;} #contacts_deletecard {position:relative; float:left; background:url('%webroot%/core/img/actions/delete.svg') no-repeat center; } #contacts_downloadcard {position:relative; float:left; background:url('%webroot%/core/img/actions/download.svg') no-repeat center; } -#contacts_propertymenu { clear: both; max-width: 15em; margin: 2em; } +#contacts_propertymenu { clear: left; float:left; max-width: 15em; margin: 2em; } #contacts_propertymenu_button { position:relative;top:0;left:0; margin: 0; } #contacts_propertymenu_dropdown { background-color: #fff; position:relative; right:0; overflow:hidden; text-overflow:ellipsis; border: thin solid #1d2d44; box-shadow: 0 3px 5px #bbb; /* -moz-box-shadow:0 0 10px #000; -webkit-box-shadow:0 0 10px #000; box-shadow:0 0 10px #000; -moz-border-radius:0.5em; -webkit-border-radius:0.5em; border-radius:0.5em; -moz-border-radius:0.5em; -webkit-border-radius:0.5em;*/ border-radius: 3px; } #contacts_propertymenu li { display: block; font-weight: bold; height: 20px; } @@ -73,10 +74,10 @@ label:hover, dt:hover { color: #333; } .contactsection { position: relative; float: left; /*max-width: 40em;*/ padding: 0.5em; height: auto: border: thin solid lightgray;/* -webkit-border-radius: 0.5em; -moz-border-radius: 0.5em; border-radius: 0.5em; background-color: #f8f8f8;*/ } #cropbox { margin: auto; } -#contacts_details_photo_wrapper { min-width: 120px; } +#contacts_details_photo_wrapper { width: 200px; } #contacts_details_photo_wrapper.wait { opacity: 0.6; filter:alpha(opacity=0.6); z-index:1000; background: url('%webroot%/core/img/loading.gif') no-repeat center center; cursor: wait; } -#contacts_details_photo { border-radius: 0.5em; border: thin solid #bbb; margin: 0.3em; background: url('%webroot%/core/img/loading.gif') no-repeat center center; -moz-box-shadow: 0 1px 3px #777; -webkit-box-shadow: 0 1px 3px #777; box-shadow: 0 1px 3px #777; } -#contacts_details_photo:hover { background: #fff; cursor: default; } +.contacts_details_photo { border-radius: 0.5em; border: thin solid #bbb; margin: 0.3em; background: url('%webroot%/core/img/loading.gif') no-repeat center center; -moz-box-shadow: 0 1px 3px #777; -webkit-box-shadow: 0 1px 3px #777; box-shadow: 0 1px 3px #777; opacity: 1; } +.contacts_details_photo:hover { background: #fff; cursor: default; } #phototools { position:absolute; margin: 5px 0 0 10px; width:auto; height:22px; padding:0px; background-color:#fff; list-style-type:none; border-radius: 0.5em; -moz-box-shadow: 0 1px 3px #777; -webkit-box-shadow: 0 1px 3px #777; box-shadow: 0 1px 3px #777; } #phototools li { display: inline; } #phototools li a { float:left; cursor:pointer; width:22px; height:22px; opacity: 0.6; } diff --git a/apps/contacts/export.php b/apps/contacts/export.php index f84a10c13888e81aebbbb17a4f370d46537dc745..ba7b06e40d25975cb6baca94d1e2cceb99008ff7 100644 --- a/apps/contacts/export.php +++ b/apps/contacts/export.php @@ -14,12 +14,16 @@ $contactid = isset($_GET['contactid']) ? $_GET['contactid'] : NULL; $nl = "\n"; if(isset($bookid)){ $addressbook = OC_Contacts_App::getAddressbook($bookid); - $cardobjects = OC_Contacts_VCard::all($bookid); + //$cardobjects = OC_Contacts_VCard::all($bookid); header('Content-Type: text/directory'); header('Content-Disposition: inline; filename=' . str_replace(' ', '_', $addressbook['displayname']) . '.vcf'); - foreach($cardobjects as $card) { - echo $card['carddata'] . $nl; + $start = 0; + while($cardobjects = OC_Contacts_VCard::all($bookid, $start, 20)){ + foreach($cardobjects as $card) { + echo $card['carddata'] . $nl; + } + $start += 20; } }elseif(isset($contactid)){ $data = OC_Contacts_App::getContactObject($contactid); diff --git a/apps/contacts/js/contacts.js b/apps/contacts/js/contacts.js index e5326ad880509fc15b9b8a3b2a32c71d4b134a9b..25fc122bf30ad45cf5d25cfd76b84c1b1913f07b 100644 --- a/apps/contacts/js/contacts.js +++ b/apps/contacts/js/contacts.js @@ -144,6 +144,31 @@ Contacts={ $('#edit_name').click(function(){Contacts.UI.Card.editName()}); $('#edit_name').keydown(function(){Contacts.UI.Card.editName()}); + $('#phototools li a').click(function() { + $(this).tipsy('hide'); + }); + $('#contacts_details_photo_wrapper').hover( + function () { + $('#phototools').slideDown(200); + }, + function () { + $('#phototools').slideUp(200); + } + ); + $('#phototools').hover( + function () { + $(this).removeClass('transparent'); + }, + function () { + $(this).addClass('transparent'); + } + ); + $('#phototools .upload').click(function() { + $('#file_upload_start').trigger('click'); + }); + $('#phototools .cloud').click(function() { + OC.dialogs.filepicker(t('contacts', 'Select photo'), Contacts.UI.Card.cloudPhotoSelected, false, 'image', true); + }); /* Initialize the photo edit dialog */ $('#edit_photo_dialog').dialog({ autoOpen: false, modal: true, height: 'auto', width: 'auto' @@ -273,7 +298,7 @@ Contacts={ update:function(id, bookid) { var newid, firstitem; if(!id) { - firstitem = $('#contacts:first-child li:first-child'); + firstitem = $('#contacts ul').first().find('li:first-child'); if(firstitem.length > 0) { newid = firstitem.data('id'); bookid = firstitem.data('bookid'); @@ -285,6 +310,7 @@ Contacts={ if(!bookid) { bookid = $('#contacts h3').first().data('id'); } + console.log('bookid: ' +bookid); var localLoadContact = function(newid, bookid) { if($('.contacts li').length > 0) { $('#contacts li[data-id="'+newid+'"]').addClass('active'); @@ -340,6 +366,9 @@ Contacts={ Contacts.UI.Card.add(';;;;;', '', '', true); return false; }, + createEntry:function(data) { + return $('<li data-id="'+data.id+'" data-bookid="'+data.addressbookid+'" role="button"><a href="'+OC.linkTo('contacts', 'index.php')+'&id='+data.id+'" style="background: url('+OC.filePath('contacts', '', 'thumbnail.php')+'?id='+data.id+') no-repeat scroll 0% 0% transparent;">'+data.displayname+'</a></li>'); + }, add:function(n, fn, aid, isnew){ // add a new contact aid = aid?aid:$('#contacts h3.active').first().data('id'); var localAddcontact = function(n, fn, aid, isnew) { @@ -1105,25 +1134,6 @@ Contacts={ loadPhotoHandlers:function(){ $('#phototools li a').tipsy('hide'); $('#phototools li a').tipsy(); - $('#phototools li a').click(function() { - $(this).tipsy('hide'); - }); - $('#contacts_details_photo_wrapper').hover( - function () { - $('#phototools').slideDown(200); - }, - function () { - $('#phototools').slideUp(200); - } - ); - $('#phototools').hover( - function () { - $(this).removeClass('transparent'); - }, - function () { - $(this).addClass('transparent'); - } - ); if(this.data.PHOTO) { $('#phototools .delete').click(function() { $(this).tipsy('hide'); @@ -1134,16 +1144,12 @@ Contacts={ $(this).tipsy('hide'); Contacts.UI.Card.editCurrentPhoto(); }); + $('#phototools .delete').show(); + $('#phototools .edit').show(); } else { $('#phototools .delete').hide(); $('#phototools .edit').hide(); } - $('#phototools .upload').click(function() { - $('#file_upload_start').trigger('click'); - }); - $('#phototools .cloud').click(function() { - OC.dialogs.filepicker(t('contacts', 'Select photo'), Contacts.UI.Card.cloudPhotoSelected, false, 'image', true); - }); }, cloudPhotoSelected:function(path){ $.getJSON(OC.filePath('contacts', 'ajax', 'oc_photo.php'),{'path':path,'id':Contacts.UI.Card.id},function(jsondata){ @@ -1158,22 +1164,33 @@ Contacts={ }); }, loadPhoto:function(refresh){ + var self = this; + var refreshstr = (refresh?'&refresh=1'+Math.random():'') $('#phototools li a').tipsy('hide'); var wrapper = $('#contacts_details_photo_wrapper'); - wrapper.addClass('wait'); + wrapper.addClass('loading').addClass('wait'); + + var img = new Image(); + $(img).load(function () { + $('img.contacts_details_photo').remove() + $(this).addClass('contacts_details_photo').hide(); + wrapper.removeClass('loading').removeClass('wait'); + $(this).insertAfter($('#phototools')).fadeIn(); + }).error(function () { + // notify the user that the image could not be loaded + $(t('contacts','something went wrong.')).insertAfter($('#phototools')); + }).attr('src', OC.linkTo('contacts', 'photo.php')+'?id='+self.id+refreshstr); + $.getJSON(OC.filePath('contacts', 'ajax', 'loadphoto.php'),{'id':this.id, 'refresh': refresh},function(jsondata){ if(jsondata.status == 'success'){ $('#contacts_details_photo_wrapper').data('checksum', jsondata.data.checksum); - wrapper.html(jsondata.data.page).ready(function(){ wrapper.removeClass('wait').tipsy() }); Contacts.UI.Card.loadPhotoHandlers(); } else{ - wrapper.removeClass('wait'); OC.dialogs.alert(jsondata.data.message, t('contacts', 'Error')); } }); $('#file_upload_form').show(); - $('#contacts_propertymenu_dropdown a[data-type="PHOTO"]').parent().hide(); }, editCurrentPhoto:function(){ $.getJSON(OC.filePath('contacts', 'ajax', 'currentphoto.php'),{'id':this.id},function(jsondata){ @@ -1209,15 +1226,15 @@ Contacts={ var target = $('#crop_target'); var form = $('#cropform'); var wrapper = $('#contacts_details_photo_wrapper'); + var self = this; wrapper.addClass('wait'); form.submit(); target.load(function(){ var response=jQuery.parseJSON(target.contents().text()); if(response != undefined && response.status == 'success'){ // load cropped photo. - wrapper.html(response.data.page).ready(function(){ wrapper.removeClass('wait') }); + self.loadPhoto(true); Contacts.UI.Card.data.PHOTO = true; - Contacts.UI.Card.loadPhotoHandlers(); }else{ OC.dialogs.alert(response.data.message, t('contacts', 'Error')); wrapper.removeClass('wait'); @@ -1342,13 +1359,18 @@ Contacts={ } return false; }, - activation:function(checkbox, bookid) - { - $.post(OC.filePath('contacts', 'ajax', 'activation.php'), { bookid: bookid, active: checkbox.checked?1:0 }, - function(data) { - if (data.status == 'success'){ - checkbox.checked = data.active == 1; - Contacts.UI.Contacts.update(); + activation:function(checkbox, bookid){ + var active = checkbox.checked; + $.post(OC.filePath('contacts', 'ajax', 'activation.php'), {bookid: bookid, active: (active?1:0)}, function(jsondata) { + if (jsondata.status == 'success'){ + if(!active) { + $('#contacts h3[data-id="'+bookid+'"],#contacts ul[data-id="'+bookid+'"]').remove(); + } else { + Contacts.UI.Contacts.update(); + } + } else { + OC.dialogs.alert(jsondata.data.message, t('contacts', 'Error')); + checkbox.checked = !active; } }); }, @@ -1443,7 +1465,7 @@ Contacts={ } } }; - xhr.open('POST', OC.filePath('contacts', 'ajax', 'uploadimport.php') + '?file='+encodeURIComponent(file.name), true); + xhr.open('POST', OC.filePath('contacts', 'ajax', 'uploadimport.php') + '?file='+encodeURIComponent(file.name)+'&requesttoken='+requesttoken, true); xhr.setRequestHeader('Cache-Control', 'no-cache'); xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest'); xhr.setRequestHeader('X_FILE_NAME', encodeURIComponent(file.name)); @@ -1532,6 +1554,7 @@ Contacts={ } }, Contacts:{ + batchnum:50, drop:function(event, ui) { var dragitem = ui.draggable, droptarget = $(this); //console.log('Drop ' + dragitem.data('id') +' on: ' + droptarget.data('id')); @@ -1563,64 +1586,81 @@ Contacts={ }); }, // Reload the contacts list. - update:function(id){ - $.getJSON(OC.filePath('contacts', 'ajax', 'contacts.php'),{},function(jsondata){ + update:function(id, aid, start){ + self = this; + console.log('update: ' + aid + ' ' + start); + var firstrun = false; + var opts = {}; + opts['startat'] = (start?start:0); + if(aid) { + opts['aid'] = aid; + } + $.getJSON(OC.filePath('contacts', 'ajax', 'contacts.php'),opts,function(jsondata){ if(jsondata.status == 'success'){ - $('#contacts').html(jsondata.data.page).ready(function() { - /*setTimeout(function() { - $('.contacts li').unbind('inview'); - $('.contacts li:visible').bind('inview', function(event, isInView, visiblePartX, visiblePartY) { - if (isInView) { - if (!$(this).find('a').attr('style')) { - $(this).find('a').css('background','url('+OC.filePath('contacts', '', 'thumbnail.php')+'?id='+$(this).data('id')+') no-repeat'); - } + var books = jsondata.data.entries; + $.each(jsondata.data.entries, function(b, book) { + if($('#contacts h3[data-id="'+b+'"]').length == 0) { + firstrun = true; + + if($('#contacts h3').length == 0) { + $('#contacts').html('<h3 class="addressbook" data-id="'+b+'">'+book.displayname+'</h3><ul class="contacts" data-id="'+b+'"></ul>'); + } else { + if(!$('#contacts h3[data-id="'+b+'"]').length) { + $('<h3 class="addressbook" data-id="'+b+'">'+book.displayname+'</h3><ul class="contacts" data-id="'+b+'"></ul>') + .appendTo('#contacts'); } - })}, 100); - setTimeout(Contacts.UI.Contacts.lazyupdate, 500);*/ - if($('#contacts h3').length > 1) { - $('#contacts h3,#contacts ul').each(function(index) { - var id = $(this).data('id'); - var accept = 'li:not([data-bookid="'+id+'"])'; - $(this).droppable({ - drop: Contacts.UI.Contacts.drop, - activeClass: 'ui-state-hover', - accept: accept - }); + } + $('#contacts h3[data-id="'+b+'"]').on('click', function(event) { + $('#contacts h3').removeClass('active'); + $(this).addClass('active'); + $('#contacts ul[data-id="'+b+'"]').slideToggle(300); + return false; }); - $('#contacts li').draggable({ - revert: 'invalid', - axis: 'y', containment: '#contacts', - scroll: true, scrollSensitivity: 100, - opacity: 0.7, helper: 'clone' + var accept = 'li:not([data-bookid="'+b+'"])'; + $('#contacts h3[data-id="'+b+'"]').droppable({ + drop: Contacts.UI.Contacts.drop, + activeClass: 'ui-state-hover', + accept: accept }); - } else { - $('#contacts h3').first().addClass('active'); + } + var contactlist = $('#contacts ul[data-id="'+b+'"]'); + for(var c in book.contacts) { + if(book.contacts[c].id == undefined) { continue; } + if($('#contacts li[data-id="'+book.contacts[c]['id']+'"][data-id="'+book.contacts[c]['bookid']+'"]').length == 0) { + var contact = Contacts.UI.Card.createEntry(book.contacts[c]); + if(c == self.batchnum-5) { + contact.bind('inview', function(event, isInView, visiblePartX, visiblePartY) { + $(this).unbind(event); + var bookid = $(this).data('bookid'); + var numsiblings = $('.contacts li[data-bookid="'+bookid+'"]').length; + if (isInView && numsiblings >= self.batchnum) { + console.log('This would be a good time to load more contacts.'); + Contacts.UI.Contacts.update(id, bookid, $('#contacts li[data-bookid="'+bookid+'"]').length); + } + }); + } + contactlist.append(contact); + } } }); - Contacts.UI.Card.update(id); + if($('#contacts h3').length > 1) { + $('#contacts li').draggable({ + revert: 'invalid', + axis: 'y', containment: '#contacts', + scroll: true, scrollSensitivity: 100, + opacity: 0.7, helper: 'clone' + }); + } else { + $('#contacts h3').first().addClass('active'); + } + if(opts['startat'] == 0) { // only update card on first load. + Contacts.UI.Card.update(); + } } else{ OC.dialogs.alert(jsondata.data.message, t('contacts', 'Error')); } }); - /*setTimeout(function() { - $('.contacts li').unbind('inview'); - $('.contacts li:visible').bind('inview', function(event, isInView, visiblePartX, visiblePartY) { - if (isInView) { - if (!$(this).find('a').attr('style')) { - $(this).find('a').css('background','url('+OC.filePath('contacts', '', 'thumbnail.php')+'?id='+$(this).data('id')+') no-repeat'); - } - } - })}, 500); - setTimeout(Contacts.UI.Contacts.lazyupdate, 500);*/ - }, - // Add thumbnails to the contact list as they become visible in the viewport. - lazyupdate:function(){ - $('.contacts li').live('inview', function(){ - if (!$(this).find('a').attr('style')) { - $(this).find('a').css('background','url('+OC.filePath('contacts', '', 'thumbnail.php')+'?id='+$(this).data('id')+') no-repeat'); - } - }); }, refreshThumbnail:function(id){ var item = $('.contacts li[data-id="'+id+'"]').find('a'); @@ -1681,13 +1721,6 @@ $(document).ready(function(){ return false; }); - $(document).on('click', '.addressbook', function(event){ - $('#contacts h3').removeClass('active'); - $(this).addClass('active'); - $(this).next().slideToggle(300); - return false; - }); - /*$('.contacts li').bind('inview', function(event, isInView, visiblePartX, visiblePartY) { if (isInView) { //NOTE: I've kept all conditions for future reference ;-) // element is now visible in the viewport diff --git a/apps/contacts/lib/addressbook.php b/apps/contacts/lib/addressbook.php index 86a41b18cf3e8ccc300f6b4a3a320a38b90a1c02..f33f4a204e70c1ebfb5a6f48cf1e43be95db22d6 100644 --- a/apps/contacts/lib/addressbook.php +++ b/apps/contacts/lib/addressbook.php @@ -41,27 +41,62 @@ class OC_Contacts_Addressbook{ /** * @brief Returns the list of addressbooks for a specific user. * @param string $uid + * @param boolean $active Only return calendars with this $active state, default(=false) is don't care * @return array or false. */ - public static function all($uid){ + public static function all($uid, $active=false){ + $values = array($uid); + $active_where = ''; + if ($active){ + $active_where = ' AND active = ?'; + $values[] = 1; + } try { - $stmt = OCP\DB::prepare( 'SELECT * FROM *PREFIX*contacts_addressbooks WHERE userid = ? ORDER BY displayname' ); - $result = $stmt->execute(array($uid)); + $stmt = OCP\DB::prepare( 'SELECT * FROM *PREFIX*contacts_addressbooks WHERE userid = ? ' . $active_where . ' ORDER BY displayname' ); + $result = $stmt->execute($values); } catch(Exception $e) { OCP\Util::writeLog('contacts',__CLASS__.'::'.__METHOD__.' exception: '.$e->getMessage(),OCP\Util::ERROR); OCP\Util::writeLog('contacts',__CLASS__.'::'.__METHOD__.' uid: '.$uid,OCP\Util::DEBUG); return false; } - $addressbooks = array(); while( $row = $result->fetchRow()){ $addressbooks[] = $row; } + if(!$active && !count($addressbooks)) { + self::addDefault($uid); + } return $addressbooks; } + /** + * @brief Get active addressbook IDs for a user. + * @param integer $uid User id. If null current user will be used. + * @return array + */ + public static function activeIds($uid = null){ + if(is_null($uid)){ + $uid = OCP\USER::getUser(); + } + $activeaddressbooks = self::all($uid, true); + $ids = array(); + foreach($activeaddressbooks as $addressbook) { + $ids[] = $addressbook['userid']; + } + return $ids; + } + + /** + * @brief Returns the list of active addressbooks for a specific user. + * @param string $uid + * @return array + */ + public static function active($uid){ + return self::all($uid, true); + } + /** * @brief Returns the list of addressbooks for a principal (DAV term of user) * @param string $principaluri @@ -186,77 +221,6 @@ class OC_Contacts_Addressbook{ return true; } - public static 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; - } - - /** - * @brief Get active addressbooks for a user. - * @param integer $uid User id. If null current user will be used. - * @return array - */ - public static function activeIds($uid = null){ - if(is_null($uid)){ - $uid = OCP\USER::getUser(); - } - $prefbooks = OCP\Config::getUserValue($uid,'contacts','openaddressbooks',null); - if(!$prefbooks){ - $addressbooks = OC_Contacts_Addressbook::all($uid); - if(count($addressbooks) == 0){ - self::addDefault($uid); - } - } - $prefbooks = OCP\Config::getUserValue($uid,'contacts','openaddressbooks',null); - return explode(';',$prefbooks); - } - - /** - * @brief Returns the list of active addressbooks for a specific user. - * @param string $uid - * @return array - */ - public static function active($uid){ - if(is_null($uid)){ - $uid = OCP\USER::getUser(); - } - $active = self::activeIds($uid); - $addressbooks = array(); - $ids_sql = join(',', array_fill(0, count($active), '?')); - $prep = 'SELECT * FROM *PREFIX*contacts_addressbooks WHERE id IN ('.$ids_sql.') ORDER BY displayname'; - try { - $stmt = OCP\DB::prepare( $prep ); - $result = $stmt->execute($active); - } catch(Exception $e) { - OCP\Util::writeLog('contacts',__CLASS__.'::'.__METHOD__.', exception: '.$e->getMessage(),OCP\Util::ERROR); - OCP\Util::writeLog('contacts',__CLASS__.'::'.__METHOD__.', uid: '.$uid,OCP\Util::DEBUG); - OCP\Util::writeLog('contacts',__CLASS__.'::'.__METHOD__.', ids: '.join(',', $active),OCP\Util::DEBUG); - OCP\Util::writeLog('contacts',__CLASS__.'::'.__METHOD__.', SQL:'.$prep,OCP\Util::DEBUG); - } - - while( $row = $result->fetchRow()){ - $addressbooks[] = $row; - } - if(!count($addressbooks)) { - self::addDefault($uid); - } - return $addressbooks; - } - /** * @brief Activates an addressbook * @param integer $id @@ -264,30 +228,16 @@ class OC_Contacts_Addressbook{ * @return boolean */ public static function setActive($id,$active){ - // Need these ones for checking uri - //$addressbook = self::find($id); - - if(is_null($id)){ - $id = 0; - } - - $openaddressbooks = self::activeIds(); - if($active) { - if(!in_array($id, $openaddressbooks)) { - $openaddressbooks[] = $id; - } - } else { - if(in_array($id, $openaddressbooks)) { - unset($openaddressbooks[array_search($id, $openaddressbooks)]); - } + $sql = 'UPDATE *PREFIX*contacts_addressbooks SET active = ? WHERE id = ?'; + OCP\Util::writeLog('contacts',__CLASS__.'::'.__METHOD__.', id: '.$id.', active: '.intval($active),OCP\Util::ERROR); + try { + $stmt = OCP\DB::prepare($sql); + $stmt->execute(array(intval($active), $id)); + return true; + } catch(Exception $e) { + OCP\Util::writeLog('contacts',__CLASS__.'::'.__METHOD__.', exception for '.$id.': '.$e->getMessage(),OCP\Util::ERROR); + return false; } - // NOTE: Ugly hack... - $openaddressbooks = self::cleanArray($openaddressbooks, false); - sort($openaddressbooks, SORT_NUMERIC); - // FIXME: I alway end up with a ';' prepending when imploding the array..? - OCP\Config::setUserValue(OCP\USER::getUser(),'contacts','openaddressbooks',implode(';', $openaddressbooks)); - - return true; } /** @@ -296,8 +246,15 @@ class OC_Contacts_Addressbook{ * @return boolean */ public static function isActive($id){ - //OCP\Util::writeLog('contacts','OC_Contacts_Addressbook::isActive('.$id.'):'.in_array($id, self::activeIds()), OCP\Util::DEBUG); - return in_array($id, self::activeIds()); + $sql = 'SELECT active FROM *PREFIX*contacts_addressbooks WHERE id = ?'; + try { + $stmt = OCP\DB::prepare( $sql ); + $result = $stmt->execute(array($id)); + $row = $result->fetchRow(); + return (bool)$row['active']; + } catch(Exception $e) { + OCP\Util::writeLog('contacts',__CLASS__.'::'.__METHOD__.', exception: '.$e->getMessage(),OCP\Util::ERROR); + } } /** diff --git a/apps/contacts/lib/hooks.php b/apps/contacts/lib/hooks.php index 9794a9c9b94a299814ee928db6a12a0a994b72d5..d91d3c565b52fcc20aa47dda028df6911b483b66 100644 --- a/apps/contacts/lib/hooks.php +++ b/apps/contacts/lib/hooks.php @@ -90,9 +90,10 @@ class OC_Contacts_Hooks{ if ($birthday) { $date = new DateTime($birthday); $vevent = new OC_VObject('VEVENT'); - $vevent->setDateTime('LAST-MODIFIED', new DateTime($vcard->REV)); + //$vevent->setDateTime('LAST-MODIFIED', new DateTime($vcard->REV)); $vevent->setDateTime('DTSTART', $date, Sabre_VObject_Element_DateTime::DATE); $vevent->setString('DURATION', 'P1D'); + $vevent->setString('UID', substr(md5(rand().time()),0,10)); // DESCRIPTION? $vevent->setString('RRULE', 'FREQ=YEARLY'); $title = str_replace('{name}', $vcard->getAsString('FN'), OC_Contacts_App::$l10n->t('{name}\'s Birthday')); @@ -101,6 +102,7 @@ class OC_Contacts_Hooks{ 'vevent' => $vevent, 'repeating' => true, 'summary' => $title, + 'calendardata' => "BEGIN:VCALENDAR\nVERSION:2.0\nPRODID:ownCloud Contacts " . OCP\App::getAppVersion('contacts') . "\n" . $vevent->serialize() . "END:VCALENDAR" ); } } diff --git a/apps/contacts/lib/vcard.php b/apps/contacts/lib/vcard.php index bf22be0de74ff7a9c31904acb4bff1776c4be3d8..e3b656056243a527a26d104dc810df175a118b23 100644 --- a/apps/contacts/lib/vcard.php +++ b/apps/contacts/lib/vcard.php @@ -47,11 +47,18 @@ class OC_Contacts_VCard{ * The cards are associative arrays. You'll find the original vCard in * ['carddata'] */ - public static function all($id){ + public static function all($id, $start=null, $num=null){ + $limitsql = ''; + if(!is_null($num)) { + $limitsql = ' LIMIT '.$num; + } + if(!is_null($start) && !is_null($num)) { + $limitsql .= ' OFFSET '.$start.' '; + } $result = null; if(is_array($id) && count($id)) { $id_sql = join(',', array_fill(0, count($id), '?')); - $prep = 'SELECT * FROM *PREFIX*contacts_cards WHERE addressbookid IN ('.$id_sql.') ORDER BY fullname'; + $prep = 'SELECT * FROM *PREFIX*contacts_cards WHERE addressbookid IN ('.$id_sql.') ORDER BY fullname '.$limitsql; try { $stmt = OCP\DB::prepare( $prep ); $result = $stmt->execute($id); @@ -63,7 +70,8 @@ class OC_Contacts_VCard{ } } elseif(is_int($id) || is_string($id)) { try { - $stmt = OCP\DB::prepare( 'SELECT * FROM *PREFIX*contacts_cards WHERE addressbookid = ? ORDER BY fullname' ); + $sql = 'SELECT * FROM *PREFIX*contacts_cards WHERE addressbookid = ? ORDER BY fullname'.$limitsql; + $stmt = OCP\DB::prepare( $sql ); $result = $stmt->execute(array($id)); } catch(Exception $e) { OCP\Util::writeLog('contacts',__CLASS__.'::'.__METHOD__.', exception: '.$e->getMessage(),OCP\Util::ERROR); diff --git a/apps/contacts/templates/index.php b/apps/contacts/templates/index.php index 0d4219c9f2d40dfffe2de58106505dbcc5073612..a8fb6c57c2cfc5d8d3454b98e0bcbedcda4aa4f0 100644 --- a/apps/contacts/templates/index.php +++ b/apps/contacts/templates/index.php @@ -9,7 +9,7 @@ </div> <div id="bottomcontrols"> <form> - <button class="svg" id="contacts_newcontact" title="<?php echo $l->t('Add Contact'); ?>"><img class="svg" src="<?php echo OCP\Util::linkTo('contacts', 'img/contact-new.svg'); ?>" alt="<?php echo $l->t('Add Contact'); ?>" /></button> + <button class="svg" id="contacts_newcontact" title="<?php echo $l->t('Add Contact'); ?>"><img class="svg" src="<?php echo OCP\Util::imagePath('contacts', 'contact-new.svg'); ?>" alt="<?php echo $l->t('Add Contact'); ?>" /></button> <button class="svg" id="chooseaddressbook" title="<?php echo $l->t('Addressbooks'); ?>"><img class="svg" src="core/img/actions/settings.svg" alt="<?php echo $l->t('Addressbooks'); ?>" /></button> </form> </div> diff --git a/apps/contacts/templates/part.contact.php b/apps/contacts/templates/part.contact.php index 5757563fe5b852ba3b3b0f153c87a70d67bcbccb..4233bffede34d7daffd57746a98e074277a40aa5 100644 --- a/apps/contacts/templates/part.contact.php +++ b/apps/contacts/templates/part.contact.php @@ -9,16 +9,19 @@ $id = isset($_['id']) ? $_['id'] : ''; <input type="hidden" class="max_human_file_size" value="(max <?php echo $_['uploadMaxHumanFilesize']; ?>)"> <input id="file_upload_start" type="file" accept="image/*" name="imagefile" /> </form> - <div id="actionbar"> - <button class="svg action" id="contacts_downloadcard" title="<?php echo $l->t('Download contact');?>"></button> - <button class="svg action" id="contacts_deletecard" title="<?php echo $l->t('Delete contact');?>"></button> - </div> <div id="contact_photo" class="contactsection"> <iframe name="file_upload_target" id='file_upload_target' src=""></iframe> <div class="tip propertycontainer" id="contacts_details_photo_wrapper" title="<?php echo $l->t('Drop photo to upload'); ?> (max <?php echo $_['uploadMaxHumanFilesize']; ?>)" data-element="PHOTO"> + <ul id="phototools" class="transparent hidden"> + <li><a class="svg delete" title="<?php echo $l->t('Delete current photo'); ?>"></a></li> + <li><a class="svg edit" title="<?php echo $l->t('Edit current photo'); ?>"></a></li> + <li><a class="svg upload" title="<?php echo $l->t('Upload new photo'); ?>"></a></li> + <li><a class="svg cloud" title="<?php echo $l->t('Select photo from ownCloud'); ?>"></a></li> + </ul> </div> + <img /> </div> <!-- contact_photo --> <div id="contact_identity" class="contactsection"> @@ -101,20 +104,23 @@ $id = isset($_['id']) ? $_['id'] : ''; </form> </div> <!-- contact_note --> - <div id="contacts_propertymenu"> - <button class="button" id="contacts_propertymenu_button"><?php echo $l->t('Add field'); ?></button> - <ul id="contacts_propertymenu_dropdown" role="menu" class="hidden"> - <li><a role="menuitem" data-type="PHOTO"><?php echo $l->t('Profile picture'); ?></a></li> - <li><a role="menuitem" data-type="ORG"><?php echo $l->t('Organization'); ?></a></li> - <li><a role="menuitem" data-type="NICKNAME"><?php echo $l->t('Nickname'); ?></a></li> - <li><a role="menuitem" data-type="BDAY"><?php echo $l->t('Birthday'); ?></a></li> - <li><a role="menuitem" data-type="TEL"><?php echo $l->t('Phone'); ?></a></li> - <li><a role="menuitem" data-type="EMAIL"><?php echo $l->t('Email'); ?></a></li> - <li><a role="menuitem" data-type="ADR"><?php echo $l->t('Address'); ?></a></li> - <li><a role="menuitem" data-type="NOTE"><?php echo $l->t('Note'); ?></a></li> - <li><a role="menuitem" data-type="URL"><?php echo $l->t('Web site'); ?></a></li> - <li><a role="menuitem" data-type="CATEGORIES"><?php echo $l->t('Groups'); ?></a></li> - </ul> + <div id="actionbar"> + <div id="contacts_propertymenu"> + <button class="button" id="contacts_propertymenu_button"><?php echo $l->t('Add field'); ?></button> + <ul id="contacts_propertymenu_dropdown" role="menu" class="hidden"> + <li><a role="menuitem" data-type="ORG"><?php echo $l->t('Organization'); ?></a></li> + <li><a role="menuitem" data-type="NICKNAME"><?php echo $l->t('Nickname'); ?></a></li> + <li><a role="menuitem" data-type="BDAY"><?php echo $l->t('Birthday'); ?></a></li> + <li><a role="menuitem" data-type="TEL"><?php echo $l->t('Phone'); ?></a></li> + <li><a role="menuitem" data-type="EMAIL"><?php echo $l->t('Email'); ?></a></li> + <li><a role="menuitem" data-type="ADR"><?php echo $l->t('Address'); ?></a></li> + <li><a role="menuitem" data-type="NOTE"><?php echo $l->t('Note'); ?></a></li> + <li><a role="menuitem" data-type="URL"><?php echo $l->t('Web site'); ?></a></li> + <li><a role="menuitem" data-type="CATEGORIES"><?php echo $l->t('Groups'); ?></a></li> + </ul> + </div> + <button class="svg action" id="contacts_downloadcard" title="<?php echo $l->t('Download contact');?>"></button> + <button class="svg action" id="contacts_deletecard" title="<?php echo $l->t('Delete contact');?>"></button> </div> </div> <!-- card --> diff --git a/apps/contacts/templates/part.contactphoto.php b/apps/contacts/templates/part.contactphoto.php deleted file mode 100644 index bddf4cc8a8190fb7b22e654cec68df6690381469..0000000000000000000000000000000000000000 --- a/apps/contacts/templates/part.contactphoto.php +++ /dev/null @@ -1,16 +0,0 @@ -<?php -$id = $_['id']; -$wattr = isset($_['width'])?'width="'.$_['width'].'"':''; -$hattr = isset($_['height'])?'height="'.$_['height'].'"':''; -$rand = isset($_['refresh'])?'&refresh='.rand():''; -?> -<ul id="phototools" class="transparent hidden"> - <li><a class="svg delete" title="<?php echo $l->t('Delete current photo'); ?>"></a></li> - <li><a class="svg edit" title="<?php echo $l->t('Edit current photo'); ?>"></a></li> - <li><a class="svg upload" title="<?php echo $l->t('Upload new photo'); ?>"></a></li> - <li><a class="svg cloud" title="<?php echo $l->t('Select photo from ownCloud'); ?>"></a></li> -</ul> -<img class="loading" id="contacts_details_photo" <?php echo $wattr; ?> <?php echo $hattr; ?> src="<?php echo OCP\Util::linkToAbsolute('contacts', 'photo.php'); ?>?id=<?php echo $id.$rand; ?>" /> -<progress id="contacts_details_photo_progress" style="display:none;" value="0" max="100">0 %</progress> - - diff --git a/apps/contacts/templates/part.contacts.php b/apps/contacts/templates/part.contacts.php deleted file mode 100644 index c33c5832e8275149b34f3ef4a1a325e49222ea72..0000000000000000000000000000000000000000 --- a/apps/contacts/templates/part.contacts.php +++ /dev/null @@ -1,10 +0,0 @@ -<?php -foreach($_['books'] as $id => $addressbook) { - echo '<h3 class="addressbook" data-id="'.$id.'">'.$addressbook['displayname'].'</h3>'; - echo '<ul class="contacts hidden" data-id="'.$id.'">'; - foreach($addressbook['contacts'] as $contact) { - echo '<li role="button" data-bookid="'.$contact['addressbookid'].'" data-id="'.$contact['id'].'"><a href="'.link_to('contacts','index.php').'&id='.$contact['id'].'" style="background: url('.link_to('contacts','thumbnail.php').'?id='.$contact['id'].') no-repeat scroll 0 0 transparent;">'.$contact['displayname'].'</a></li>'; - } - echo '</ul>'; -} -?> diff --git a/apps/files/js/files.js b/apps/files/js/files.js index 3ba473e023d6f8b60d3f4f2b6940ec4663df5a2a..86c5185bf728b6752b2f924375531259bdc61a7e 100644 --- a/apps/files/js/files.js +++ b/apps/files/js/files.js @@ -451,7 +451,7 @@ $(document).ready(function() { $(this).append(input); input.focus(); input.change(function(){ - var name=$(this).val(); + var name=getUniqueName($(this).val()); if(type != 'web' && name.indexOf('/')!=-1){ $('#notification').text(t('files','Invalid name, \'/\' is not allowed.')); $('#notification').fadeIn(); @@ -496,6 +496,7 @@ $(document).ready(function() { }else{//or the domain localName=(localName.match(/:\/\/(.[^/]+)/)[1]).replace('www.',''); } + localName = getUniqueName(localName); $.post( OC.filePath('files','ajax','newfile.php'), {dir:$('#dir').val(),source:name,filename:localName}, @@ -737,7 +738,10 @@ getMimeIcon.cache={}; function getUniqueName(name){ if($('tr').filterAttr('data-file',name).length>0){ var parts=name.split('.'); - var extension=parts.pop(); + var extension = ""; + if (parts.length > 1) { + extension=parts.pop(); + } var base=parts.join('.'); numMatch=base.match(/\((\d+)\)/); var num=2; @@ -747,7 +751,10 @@ function getUniqueName(name){ base.pop(); base=base.join('(').trim(); } - name=base+' ('+num+').'+extension; + name=base+' ('+num+')'; + if (extension) { + name = name+'.'+extension; + } return getUniqueName(name); } return name; diff --git a/apps/files_encryption/tests/proxy.php b/apps/files_encryption/tests/proxy.php index fcfc4cfb9f0bcd43bb76e5705c09cff82d005eb7..5463836a209da9bffe2aec5b15478ced6c065b79 100644 --- a/apps/files_encryption/tests/proxy.php +++ b/apps/files_encryption/tests/proxy.php @@ -11,6 +11,8 @@ class Test_CryptProxy extends UnitTestCase { private $oldKey; public function setUp(){ + $user=OC_User::getUser(); + $this->oldConfig=OCP\Config::getAppValue('files_encryption','enable_encryption','true'); OCP\Config::setAppValue('files_encryption','enable_encryption','true'); $this->oldKey=isset($_SESSION['enckey'])?$_SESSION['enckey']:null; @@ -30,10 +32,12 @@ class Test_CryptProxy extends UnitTestCase { OC_Filesystem::clearMounts(); OC_Filesystem::mount('OC_Filestorage_Temporary',array(),'/'); + OC_Filesystem::init('/'.$user.'/files'); + //set up the users home folder in the temp storage $rootView=new OC_FilesystemView(''); - $rootView->mkdir('/'.OC_User::getUser()); - $rootView->mkdir('/'.OC_User::getUser().'/files'); + $rootView->mkdir('/'.$user); + $rootView->mkdir('/'.$user.'/files'); } public function tearDown(){ diff --git a/apps/files_external/ajax/addRootCertificate.php b/apps/files_external/ajax/addRootCertificate.php new file mode 100644 index 0000000000000000000000000000000000000000..33cd64d2c7a6e261d39876b9a8d41b5407b1fe98 --- /dev/null +++ b/apps/files_external/ajax/addRootCertificate.php @@ -0,0 +1,12 @@ +<?php + +OCP\JSON::checkAppEnabled('files_external'); + +$view = \OCP\Files::getStorage("files_external"); +$from = $_FILES['rootcert_import']['tmp_name']; +$to = \OCP\Config::getSystemValue('datadirectory').$view->getAbsolutePath("").$_FILES['rootcert_import']['name']; +move_uploaded_file($from, $to); + +header("Location: settings/personal.php"); +exit; +?> \ No newline at end of file diff --git a/apps/files_external/ajax/removeRootCertificate.php b/apps/files_external/ajax/removeRootCertificate.php new file mode 100644 index 0000000000000000000000000000000000000000..05f2fdef2d16445f62bead338df92acf585cb737 --- /dev/null +++ b/apps/files_external/ajax/removeRootCertificate.php @@ -0,0 +1,9 @@ +<?php + +OCP\JSON::checkAppEnabled('files_external'); + +$view = \OCP\Files::getStorage("files_external"); +$cert = $_POST['cert']; +$file = \OCP\Config::getSystemValue('datadirectory').$view->getAbsolutePath("").$cert; +unlink($file); +?> \ No newline at end of file diff --git a/apps/files_external/js/dropbox.js b/apps/files_external/js/dropbox.js index 67f3c46a6ed3f2b9534fb307b1dfa8426bdb9fc6..08796cbbdc9c23215bb6ea6b8448c5f744ffffcd 100644 --- a/apps/files_external/js/dropbox.js +++ b/apps/files_external/js/dropbox.js @@ -23,7 +23,6 @@ $(document).ready(function() { }); } } - return false; } }); diff --git a/apps/files_external/js/google.js b/apps/files_external/js/google.js index 84c74c57421a221255ab201d176b83da388ffb79..55042194c7db5c9be799f7182e13dfe20f7cbbea 100644 --- a/apps/files_external/js/google.js +++ b/apps/files_external/js/google.js @@ -24,7 +24,6 @@ $(document).ready(function() { }); } } - return false; } }); diff --git a/apps/files_external/js/settings.js b/apps/files_external/js/settings.js index 57188a6a266e4bbcb8163fc7fe5ba4959c3e7e55..0d942e7845b85fa457a8b29ae1441df90f6d03b0 100644 --- a/apps/files_external/js/settings.js +++ b/apps/files_external/js/settings.js @@ -1,4 +1,4 @@ -OC.MountConfig={ +OC.MountConfig={ saveStorage:function(tr) { var mountPoint = $(tr).find('.mountPoint input').val(); if (mountPoint == '') { @@ -27,7 +27,7 @@ OC.MountConfig={ } }); if (addMountPoint) { - if ($('#externalStorage').data('admin')) { + if ($('#externalStorage').data('admin') === true) { var isPersonal = false; var multiselect = $(tr).find('.chzn-select').val(); var oldGroups = $(tr).find('.applicable').data('applicable-groups'); @@ -68,12 +68,12 @@ OC.MountConfig={ } $(document).ready(function() { - $('.chzn-select').chosen(); $('#selectBackend').live('change', function() { var tr = $(this).parent().parent(); - $('#externalStorage tbody').last().append($(tr).clone()); + $('#externalStorage tbody').append($(tr).clone()); + $('#externalStorage tbody tr').last().find('.mountPoint input').val(''); var selected = $(this).find('option:selected').text(); var backendClass = $(this).val(); $(this).parent().text(selected); @@ -103,6 +103,7 @@ $(document).ready(function() { }); $('.chz-select').chosen(); $(tr).find('td').last().attr('class', 'remove'); + $(tr).find('td').last().removeAttr('style'); $(tr).removeAttr('id'); $(this).remove(); }); @@ -114,10 +115,13 @@ $(document).ready(function() { $('td.remove>img').live('click', function() { var tr = $(this).parent().parent(); var mountPoint = $(tr).find('.mountPoint input').val(); - if (mountPoint == '') { - return false; + if (!mountPoint) { + var row=this.parentNode.parentNode; + $.post(OC.filePath('files_external', 'ajax', 'removeRootCertificate.php'), { cert: row.id }); + $(tr).remove(); + return true; } - if ($('#externalStorage').data('admin')) { + if ($('#externalStorage').data('admin') === true) { var isPersonal = false; var multiselect = $(tr).find('.chzn-select').val(); $.each(multiselect, function(index, value) { diff --git a/apps/files_external/lib/amazons3.php b/apps/files_external/lib/amazons3.php index b8e5b9b079be31fd893d20993b67f02c306e7cce..9feb490dac0c91c5e2b94b9863b9e7583484f1c9 100644 --- a/apps/files_external/lib/amazons3.php +++ b/apps/files_external/lib/amazons3.php @@ -96,8 +96,8 @@ class OC_Filestorage_AmazonS3 extends OC_Filestorage_Common { foreach ($response->body->CommonPrefixes as $object) { $files[] = basename($object->Prefix); } - OC_FakeDirStream::$dirs['amazons3'] = $files; - return opendir('fakedir://amazons3'); + OC_FakeDirStream::$dirs['amazons3'.$path] = $files; + return opendir('fakedir://amazons3'.$path); } return false; } diff --git a/apps/files_external/lib/config.php b/apps/files_external/lib/config.php index 5b9e00a3783aa6d8b1eea943d12ba3c6d12c75db..4e82e6b254859fd92911e25266e4e971055a6e09 100755 --- a/apps/files_external/lib/config.php +++ b/apps/files_external/lib/config.php @@ -45,7 +45,7 @@ class OC_Mount_Config { 'OC_Filestorage_FTP' => array('backend' => 'FTP', 'configuration' => array('host' => 'URL', 'user' => 'Username', 'password' => '*Password', 'root' => '&Root', 'secure' => '!Secure ftps://')), 'OC_Filestorage_Google' => array('backend' => 'Google Drive', 'configuration' => array('token' => '#token', 'token_secret' => '#token secret'), 'custom' => 'google'), 'OC_Filestorage_SWIFT' => array('backend' => 'OpenStack Swift', 'configuration' => array('host' => 'URL', 'user' => 'Username', 'token' => '*Token', 'root' => '&Root', 'secure' => '!Secure ftps://')), - 'OC_Filestorage_SMB' => array('backend' => 'SMB', 'configuration' => array('host' => 'URL', 'user' => 'Username', 'password' => '*Password', 'root' => '&Root')), + 'OC_Filestorage_SMB' => array('backend' => 'SMB', 'configuration' => array('host' => 'URL', 'user' => 'Username', 'password' => '*Password', 'share' => 'Share', 'root' => '&Root')), 'OC_Filestorage_DAV' => array('backend' => 'WebDAV', 'configuration' => array('host' => 'URL', 'user' => 'Username', 'password' => '*Password', 'root' => '&Root', 'secure' => '!Secure https://')) ); } @@ -237,6 +237,21 @@ class OC_Mount_Config { $content .= ");\n?>"; @file_put_contents($file, $content); } + + /** + * Returns all user uploaded ssl root certificates + * @return array + */ + public static function getCertificates() { + $view = \OCP\Files::getStorage('files_external'); + $path=\OCP\Config::getSystemValue('datadirectory').$view->getAbsolutePath(""); + $result = array(); + $handle = opendir($path); + while (false !== ($file = readdir($handle))) { + if($file != '.' && $file != '..') $result[] = $file; + } + return $result; + } } diff --git a/apps/files_external/lib/dropbox.php b/apps/files_external/lib/dropbox.php index 6f1a154a1225e252049aa741dc75a01fd14486fc..35663d431f8e30637c7fc10f49156653451f5143 100755 --- a/apps/files_external/lib/dropbox.php +++ b/apps/files_external/lib/dropbox.php @@ -33,7 +33,6 @@ class OC_Filestorage_Dropbox extends OC_Filestorage_Common { $oauth = new Dropbox_OAuth_Curl($params['app_key'], $params['app_secret']); $oauth->setToken($params['token'], $params['token_secret']); $this->dropbox = new Dropbox_API($oauth, 'dropbox'); - } private function getMetaData($path, $list = false) { @@ -71,11 +70,16 @@ class OC_Filestorage_Dropbox extends OC_Filestorage_Common { } public function mkdir($path) { - return $this->dropbox->createFolder($path); + try { + $this->dropbox->createFolder($path); + return true; + } catch (Exception $exception) { + return false; + } } public function rmdir($path) { - return $this->dropbox->delete($path); + return $this->unlink($path); } public function opendir($path) { @@ -84,8 +88,8 @@ class OC_Filestorage_Dropbox extends OC_Filestorage_Common { foreach ($contents as $file) { $files[] = basename($file['path']); } - OC_FakeDirStream::$dirs['dropbox'] = $files; - return opendir('fakedir://dropbox'); + OC_FakeDirStream::$dirs['dropbox'.$path] = $files; + return opendir('fakedir://dropbox'.$path); } return false; } @@ -115,11 +119,11 @@ class OC_Filestorage_Dropbox extends OC_Filestorage_Common { } public function is_readable($path) { - return self::file_exists($path); + return $this->file_exists($path); } public function is_writable($path) { - return self::file_exists($path); + return $this->file_exists($path); } public function file_exists($path) { @@ -133,7 +137,30 @@ class OC_Filestorage_Dropbox extends OC_Filestorage_Common { } public function unlink($path) { - return $this->dropbox->delete($path); + try { + $this->dropbox->delete($path); + return true; + } catch (Exception $exception) { + return false; + } + } + + public function rename($path1, $path2) { + try { + $this->dropbox->move($path1, $path2); + return true; + } catch (Exception $exception) { + return false; + } + } + + public function copy($path1, $path2) { + try { + $this->dropbox->copy($path1, $path2); + return true; + } catch (Exception $exception) { + return false; + } } public function fopen($path, $mode) { @@ -141,8 +168,13 @@ class OC_Filestorage_Dropbox extends OC_Filestorage_Common { case 'r': case 'rb': $tmpFile = OC_Helper::tmpFile(); - file_put_contents($tmpFile, $this->dropbox->getFile($path)); - return fopen($tmpFile, 'r'); + try { + $data = $this->dropbox->getFile($path); + file_put_contents($tmpFile, $data); + return fopen($tmpFile, 'r'); + } catch (Exception $exception) { + return false; + } case 'w': case 'wb': case 'a': @@ -175,9 +207,11 @@ class OC_Filestorage_Dropbox extends OC_Filestorage_Common { public function writeBack($tmpFile) { if (isset(self::$tempFiles[$tmpFile])) { $handle = fopen($tmpFile, 'r'); - $response = $this->dropbox->putFile(self::$tempFiles[$tmpFile], $handle); - if ($response) { + try { + $response = $this->dropbox->putFile(self::$tempFiles[$tmpFile], $handle); unlink($tmpFile); + } catch (Exception $exception) { + } } } @@ -192,10 +226,12 @@ class OC_Filestorage_Dropbox extends OC_Filestorage_Common { } public function free_space($path) { - if ($info = $this->dropbox->getAccountInfo()) { + try { + $info = $this->dropbox->getAccountInfo(); return $info['quota_info']['quota'] - $info['quota_info']['normal']; + } catch (Exception $exception) { + return false; } - return false; } public function touch($path, $mtime = null) { diff --git a/apps/files_external/lib/google.php b/apps/files_external/lib/google.php index fe60a06629abf246d232ecaa21d464e96207d6bb..41b560ae84e6f8a19eda60933095a4e6e151f73c 100644 --- a/apps/files_external/lib/google.php +++ b/apps/files_external/lib/google.php @@ -237,8 +237,8 @@ class OC_Filestorage_Google extends OC_Filestorage_Common { $this->entries[$name] = $entry; } } - OC_FakeDirStream::$dirs['google'] = $files; - return opendir('fakedir://google'); + OC_FakeDirStream::$dirs['google'.$path] = $files; + return opendir('fakedir://google'.$path); } public function stat($path) { diff --git a/apps/files_external/lib/webdav.php b/apps/files_external/lib/webdav.php index d136f04f3eb5e7f90ea5bd7c2ffbbc761b0ee256..dda8afe9f2ae499fdf73d37c504736b77804a430 100644 --- a/apps/files_external/lib/webdav.php +++ b/apps/files_external/lib/webdav.php @@ -20,10 +20,14 @@ class OC_FileStorage_DAV extends OC_Filestorage_Common{ private static $tempFiles=array(); public function __construct($params){ - $this->host=$params['host']; + $host = $params['host']; + //remove leading http[s], will be generated in createBaseUri() + if (substr($host,0,8) == "https://") $host = substr($host, 8); + else if (substr($host,0,7) == "http://") $host = substr($host, 7); + $this->host=$host; $this->user=$params['user']; $this->password=$params['password']; - $this->secure=isset($params['secure'])?(bool)$params['secure']:false; + $this->secure=(isset($params['secure']) && $params['secure'] == 'true')?true:false; $this->root=isset($params['root'])?$params['root']:'/'; if(!$this->root || $this->root[0]!='/'){ $this->root='/'.$this->root; @@ -46,7 +50,7 @@ class OC_FileStorage_DAV extends OC_Filestorage_Common{ private function createBaseUri(){ $baseUri='http'; if($this->secure){ - $baseUri.'s'; + $baseUri.='s'; } $baseUri.='://'.$this->host.$this->root; return $baseUri; @@ -69,13 +73,15 @@ class OC_FileStorage_DAV extends OC_Filestorage_Common{ $stripLength=strlen($this->root)+strlen($path); $id=md5('webdav'.$this->root.$path); OC_FakeDirStream::$dirs[$id]=array(); + $skip = true; foreach($response as $file=>$data){ - //strip root and path - $file=trim(substr($file,$stripLength)); - $file=trim($file,'/'); - if($file){ - OC_FakeDirStream::$dirs[$id][]=$file; + // Skip the first file, because it is the current directory + if ($skip) { + $skip = false; + continue; } + $file = urldecode(basename($file)); + OC_FakeDirStream::$dirs[$id][]=$file; } return opendir('fakedir://'.$id); }catch(Exception $e){ @@ -90,6 +96,8 @@ class OC_FileStorage_DAV extends OC_Filestorage_Common{ $responseType=$response["{DAV:}resourcetype"]->resourceType; return (count($responseType)>0 and $responseType[0]=="{DAV:}collection")?'dir':'file'; }catch(Exception $e){ + error_log($e->getMessage()); + \OCP\Util::writeLog("webdav client", \OCP\Util::sanitizeHTML($e->getMessage()), \OCP\Util::ERROR); return false; } } @@ -240,15 +248,11 @@ class OC_FileStorage_DAV extends OC_Filestorage_Common{ $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(); - } + return array( + 'mtime'=>strtotime($response['{DAV:}getlastmodified']), + 'size'=>(int)isset($response['{DAV:}getcontentlength']) ? $response['{DAV:}getcontentlength'] : 0, + 'ctime'=>-1, + ); }catch(Exception $e){ return array(); } diff --git a/apps/files_external/personal.php b/apps/files_external/personal.php index 32e087424429720a1b0d88029b928e4087a5868f..dec501741b608736d48814950f7afc56e394fdd2 100755 --- a/apps/files_external/personal.php +++ b/apps/files_external/personal.php @@ -26,8 +26,9 @@ $backends = OC_Mount_Config::getBackends(); // Remove local storage unset($backends['OC_Filestorage_Local']); $tmpl = new OCP\Template('files_external', 'settings'); -$tmpl->assign('isAdminPage', false); +$tmpl->assign('isAdminPage', false, false); $tmpl->assign('mounts', OC_Mount_Config::getPersonalMountPoints()); +$tmpl->assign('certs', OC_Mount_Config::getCertificates()); $tmpl->assign('backends', $backends); return $tmpl->fetchPage(); diff --git a/apps/files_external/settings.php b/apps/files_external/settings.php index 983855ecdcc3fbfac13824f725d80a56e0d9a3da..acc9036b299822f894cc40f713b93afa8fa4a658 100644 --- a/apps/files_external/settings.php +++ b/apps/files_external/settings.php @@ -23,7 +23,7 @@ OCP\Util::addScript('files_external', 'settings'); OCP\Util::addStyle('files_external', 'settings'); $tmpl = new OCP\Template('files_external', 'settings'); -$tmpl->assign('isAdminPage', true); +$tmpl->assign('isAdminPage', true, false); $tmpl->assign('mounts', OC_Mount_Config::getSystemMountPoints()); $tmpl->assign('backends', OC_Mount_Config::getBackends()); $tmpl->assign('groups', OC_Group::getGroups()); diff --git a/apps/files_external/templates/settings.php b/apps/files_external/templates/settings.php index 6c37df8001eb93004d57c5234168cee8aa9d2d06..dccc0913f2366318f8dcdc1b491dda9c72908312 100644 --- a/apps/files_external/templates/settings.php +++ b/apps/files_external/templates/settings.php @@ -1,7 +1,7 @@ -<form id="files_external"> +<form id="files_external" method="post" enctype="multipart/form-data" action="/owncloud/?app=files_external&getfile=ajax%2FaddRootCertificate.php"> <fieldset class="personalblock"> <legend><strong><?php echo $l->t('External Storage'); ?></strong></legend> - <table id="externalStorage" data-admin="<?php echo json_encode($_['isAdminPage']); ?>"> + <table id="externalStorage" data-admin='<?php echo json_encode($_['isAdminPage']); ?>'> <thead> <tr> <th><?php echo $l->t('Mount point'); ?></th> @@ -39,7 +39,7 @@ <?php elseif(strpos($placeholder, '!') !== false): ?> <label><input type="checkbox" data-parameter="<?php echo $parameter; ?>" <?php if ($value == 'true') echo ' checked="checked"'; ?> /><?php echo substr($placeholder, 1); ?></label> <?php elseif (strpos($placeholder, '&') !== false): ?> - <input type="text" class="optional" data-parameter="<?php echo $parameter; ?>" value="<?php echo $value; ?>" placeholder="<?php echo substr($placeholder, 1); ?>" /> + <input type="text" class="optional" data-parameter="<?php echo $parameter; ?>" value="<?php echo $value; ?>" placeholder="<?php echo substr($placeholder, 5); ?>" /> <?php elseif (strpos($placeholder, '#') !== false): ?> <input type="hidden" data-parameter="<?php echo $parameter; ?>" value="<?php echo $value; ?>" /> <?php else: ?> @@ -74,11 +74,34 @@ </select> </td> <?php endif; ?> - <td <?php if ($mountPoint != '') echo 'class="remove"'; ?>><img alt="<?php echo $l->t('Delete'); ?>" title="<?php echo $l->t('Delete'); ?>" class="svg action" src="<?php echo image_path('core', 'actions/delete.svg'); ?>" /></td> + <td <?php echo ($mountPoint != '') ? 'class="remove"' : 'style="visibility:hidden;"'; ?>><img alt="<?php echo $l->t('Delete'); ?>" title="<?php echo $l->t('Delete'); ?>" class="svg action" src="<?php echo image_path('core', 'actions/delete.svg'); ?>" /></td> </tr> <?php endforeach; ?> </tbody> </table> + <br /> + + <?php if (!$_['isAdminPage']): ?> + <table id="sslCertificate" data-admin='<?php echo json_encode($_['isAdminPage']); ?>'> + <thead> + <tr> + <th><?php echo $l->t('SSL root certificates'); ?></th> + <th> </th> + </tr> + </thead> + <tbody width="100%"> + <?php foreach ($_['certs'] as $rootCert): ?> + <tr id="<?php echo $rootCert ?>"> + <td class="rootCert"><?php echo $rootCert ?></td> + <td <?php echo ($rootCert != '') ? 'class="remove"' : 'style="visibility:hidden;"'; ?>><img alt="<?php echo $l->t('Delete'); ?>" title="<?php echo $l->t('Delete'); ?>" class="svg action" src="<?php echo image_path('core', 'actions/delete.svg'); ?>" /></td> + </tr> + <?php endforeach; ?> + </tbody> + </table> + <input type="file" id="rootcert_import" name="rootcert_import" style="width:230px;"> + <input type="submit" name="cert_import" value="<?php echo $l->t('Import Root Certificate'); ?>" /> + <?php endif; ?> + <?php if ($_['isAdminPage']): ?> <br /> <input type="checkbox" name="allowUserMounting" id="allowUserMounting" value="1" <?php if ($_['allowUserMounting'] == 'yes') echo ' checked="checked"'; ?> /> @@ -86,4 +109,4 @@ <em><?php echo $l->t('Allow users to mount their own external storage'); ?></em> <?php endif; ?> </fieldset> -</form> \ No newline at end of file +</form> diff --git a/apps/files_sharing/js/share.js b/apps/files_sharing/js/share.js index 9194d2240ab153b198c92d2d8cbb46151847c0e9..39e6bd7859084380a77c1e3fcb202bbd741306d5 100644 --- a/apps/files_sharing/js/share.js +++ b/apps/files_sharing/js/share.js @@ -360,7 +360,8 @@ $(document).ready(function() { $(this).select(); }); - $('#emailPrivateLink').live('submit', function() { + $('#emailPrivateLink').live('submit', function(event) { + event.preventDefault(); OC.Share.emailPrivateLink(); }); }); \ No newline at end of file diff --git a/apps/files_sharing/sharedstorage.php b/apps/files_sharing/sharedstorage.php index fed1b834fa3a923e38b4427388e70b6055952ed3..4138fc2b399303fbf0037169ac53fe26f1c62f3e 100644 --- a/apps/files_sharing/sharedstorage.php +++ b/apps/files_sharing/sharedstorage.php @@ -81,8 +81,8 @@ class OC_Filestorage_Shared extends OC_Filestorage_Common { $files[] = basename($item['target']); } } - OC_FakeDirStream::$dirs['shared']=$files; - return opendir('fakedir://shared'); + OC_FakeDirStream::$dirs['shared'.$path] = $files; + return opendir('fakedir://shared'.$path); } else { $source = $this->getSource($path); if ($source) { diff --git a/apps/files_texteditor/ajax/loadfile.php b/apps/files_texteditor/ajax/loadfile.php index c263306e71917b5805795f8d62ac7e44746e318f..5a5affa46be68371d979d3f5c8c8a1172b031e0b 100644 --- a/apps/files_texteditor/ajax/loadfile.php +++ b/apps/files_texteditor/ajax/loadfile.php @@ -43,6 +43,7 @@ if(!empty($filename)) { $mtime = OC_Filesystem::filemtime($path); $filecontents = OC_Filesystem::file_get_contents($path); + $filecontents = iconv(mb_detect_encoding($filecontents), "UTF-8", $filecontents); OCP\JSON::success(array('data' => array('filecontents' => $filecontents, 'write' => 'false', 'mtime' => $mtime))); } } else { diff --git a/apps/files_texteditor/ajax/savefile.php b/apps/files_texteditor/ajax/savefile.php index f789112d7d7b438450aafe6ec99a2ad2c6e2ccba..961db7105e3371dd7da4036a94cc12dae1e6940f 100644 --- a/apps/files_texteditor/ajax/savefile.php +++ b/apps/files_texteditor/ajax/savefile.php @@ -48,6 +48,7 @@ if($path != '' && $mtime != '' && $filecontents) // Save file if(OC_Filesystem::is_writable($path)) { + $filecontents = iconv(mb_detect_encoding($filecontents), "UTF-8", $filecontents); OC_Filesystem::file_put_contents($path, $filecontents); // Clear statcache clearstatcache(); diff --git a/apps/files_versions/ajax/expireAll.php b/apps/files_versions/ajax/expireAll.php index f9cd74aed025f2af1e9079d6654a154caddcaf3e..238e3bdad4ddb31532a7f35ff1d487dfe20cf227 100644 --- a/apps/files_versions/ajax/expireAll.php +++ b/apps/files_versions/ajax/expireAll.php @@ -28,7 +28,9 @@ OCP\JSON::checkLoggedIn(); OCP\App::checkAppEnabled('files_versions'); -if( OCA_Versions\Storage::expireAll() ){ +$versions = new OCA_Versions\Storage( new OC_FilesystemView('') ); + +if( $versions->expireAll() ){ OCP\JSON::success(); die(); diff --git a/apps/files_versions/ajax/getVersions.php b/apps/files_versions/ajax/getVersions.php index bee6054333977f0a0858b8602f071d60e4a3fc96..1a0e21732ccb9fb4be6b2288777eb1d0425012c9 100644 --- a/apps/files_versions/ajax/getVersions.php +++ b/apps/files_versions/ajax/getVersions.php @@ -1,11 +1,8 @@ <?php OCP\JSON::checkAppEnabled('files_versions'); -require_once('apps/files_versions/versions.php'); - $userDirectory = "/".OCP\USER::getUser()."/files"; $source = $_GET['source']; -$source = strip_tags( $source ); if( OCA_Versions\Storage::isversioned( $source ) ) { @@ -14,9 +11,7 @@ if( OCA_Versions\Storage::isversioned( $source ) ) { $versionsFormatted = array(); foreach ( $versions AS $version ) { - - $versionsFormatted[] = OCP\Util::formatDate( $version ); - + $versionsFormatted[] = OCP\Util::formatDate( $version['version'] ); } $versionsSorted = array_reverse( $versions ); diff --git a/apps/files_versions/ajax/rollbackVersion.php b/apps/files_versions/ajax/rollbackVersion.php index 127592f3b58095bf55c48b95ae13562c1a049b0c..8d1092f8b8e217f03bf59f97ec3896d6cd90beb3 100644 --- a/apps/files_versions/ajax/rollbackVersion.php +++ b/apps/files_versions/ajax/rollbackVersion.php @@ -2,8 +2,6 @@ OCP\JSON::checkAppEnabled('files_versions'); -require_once('apps/files_versions/versions.php'); - $userDirectory = "/".OCP\USER::getUser()."/files"; $file = $_GET['file']; diff --git a/apps/files_versions/appinfo/app.php b/apps/files_versions/appinfo/app.php index bd06dc0ced3c12b05a7e286039ffaa87d126e7cf..dba612e4b79399213c5a62306769dbec4a93e274 100644 --- a/apps/files_versions/appinfo/app.php +++ b/apps/files_versions/appinfo/app.php @@ -1,6 +1,8 @@ <?php -require_once('files_versions/versions.php'); +//require_once('files_versions/versions.php'); +OC::$CLASSPATH['OCA_Versions\Storage'] = 'apps/files_versions/lib/versions.php'; +OC::$CLASSPATH['OCA_Versions\Hooks'] = 'apps/files_versions/lib/hooks.php'; OCP\App::registerAdmin('files_versions', 'settings'); OCP\App::registerPersonal('files_versions','settings-personal'); @@ -8,4 +10,7 @@ OCP\App::registerPersonal('files_versions','settings-personal'); OCP\Util::addscript('files_versions', 'versions'); // Listen to write signals -OCP\Util::connectHook('OC_Filesystem', 'post_write', "OCA_Versions\Storage", "write_hook"); +OCP\Util::connectHook('OC_Filesystem', 'post_write', "OCA_Versions\Hooks", "write_hook"); +// Listen to delete and rename signals +OCP\Util::connectHook('OC_Filesystem', 'delete', "OCA_Versions\Storage", "removeVersions"); +OCP\Util::connectHook('OC_Filesystem', 'rename', "OCA_Versions\Storage", "renameVersions"); \ No newline at end of file diff --git a/apps/files_versions/history.php b/apps/files_versions/history.php index cb4726e8d0e735a4e3fc177d489a5e9abb11ffde..e3332d7cdb6086319356604f41e37ba844927125 100644 --- a/apps/files_versions/history.php +++ b/apps/files_versions/history.php @@ -30,21 +30,22 @@ if ( isset( $_GET['path'] ) ) { $path = $_GET['path']; $path = strip_tags( $path ); $tmpl->assign( 'path', $path ); + $versions = new OCA_Versions\Storage( new OC_FilesystemView('') ); // roll back to old version if button clicked if( isset( $_GET['revert'] ) ) { - if( \OCA_Versions\Storage::rollback( $path, $_GET['revert'] ) ) { + if( $versions->rollback( $path, $_GET['revert'] ) ) { $tmpl->assign( 'outcome_stat', 'success' ); - $tmpl->assign( 'outcome_msg', "File {$_GET['path']} was reverted to version ".OCP\Util::formatDate( $_GET['revert'] ) ); + $tmpl->assign( 'outcome_msg', "File {$_GET['path']} was reverted to version ".OCP\Util::formatDate( doubleval($_GET['revert']) ) ); } else { $tmpl->assign( 'outcome_stat', 'failure' ); - $tmpl->assign( 'outcome_msg', "File {$_GET['path']} could not be reverted to version ".OCP\Util::formatDate( $_GET['revert'] ) ); + $tmpl->assign( 'outcome_msg', "File {$_GET['path']} could not be reverted to version ".OCP\Util::formatDate( doubleval($_GET['revert']) ) ); } diff --git a/apps/files_versions/js/versions.js b/apps/files_versions/js/versions.js index 82d569fa0f6fe7500355d207483a56759455e969..a090fde446e1f96f970154647f1c1b82a4e35df3 100644 --- a/apps/files_versions/js/versions.js +++ b/apps/files_versions/js/versions.js @@ -104,9 +104,9 @@ function createVersionsDropdown(filename, files) { } function addVersion(revision ) { - name=formatDate(revision*1000); + name=formatDate(revision.version*1000); var version=$('<option/>'); - version.attr('value',revision); + version.attr('value',revision.version); version.text(name); // } else { diff --git a/apps/files_versions/lib/hooks.php b/apps/files_versions/lib/hooks.php new file mode 100644 index 0000000000000000000000000000000000000000..8a7467053296c132f18d67ab67034e8f3c3abda5 --- /dev/null +++ b/apps/files_versions/lib/hooks.php @@ -0,0 +1,35 @@ +<?php +/** + * Copyright (c) 2012 Sam Tuke <samtuke@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +/** + * This class contains all hooks. + */ + +namespace OCA_Versions; + +class Hooks { + + /** + * listen to write event. + */ + public static function write_hook( $params ) { + + if(\OCP\Config::getSystemValue('files_versions', Storage::DEFAULTENABLED)=='true') { + + $versions = new Storage( new \OC_FilesystemView('') ); + + $path = $params[\OC_Filesystem::signal_param_path]; + + if($path<>'') $versions->store( $path ); + + } + } + +} + +?> diff --git a/apps/files_versions/versions.php b/apps/files_versions/lib/versions.php similarity index 75% rename from apps/files_versions/versions.php rename to apps/files_versions/lib/versions.php index 9c0829ff1dee8b2a067d5275aa95a651c048ae58..fb78e0a56c046854b226e44dcbd7d5d3ab350c89 100644 --- a/apps/files_versions/versions.php +++ b/apps/files_versions/lib/versions.php @@ -1,313 +1,363 @@ -<?php -/** - * Copyright (c) 2012 Frank Karlitschek <frank@owncloud.org> - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -/** - * Versions - * - * A class to handle the versioning of files. - */ - -namespace OCA_Versions; - -class Storage { - - - // config.php configuration: - // - files_versions - // - files_versionsfolder - // - files_versionsblacklist - // - files_versionsmaxfilesize - // - files_versionsinterval - // - files_versionmaxversions - // - // todo: - // - port to oc_filesystem to enable network transparency - // - implement expire all function. And find a place to call it ;-) - // - add transparent compression. first test if it´s worth it. - - const DEFAULTENABLED=true; - const DEFAULTFOLDER='versions'; - const DEFAULTBLACKLIST='avi mp3 mpg mp4 ctmp'; - const DEFAULTMAXFILESIZE=1048576; // 10MB - const DEFAULTMININTERVAL=1; // 2 min - const DEFAULTMAXVERSIONS=50; - - /** - * init the versioning and create the versions folder. - */ - public static function init() { - if(\OCP\Config::getSystemValue('files_versions', Storage::DEFAULTENABLED)=='true') { - // create versions folder - $foldername=\OCP\Config::getSystemValue('datadirectory').'/'. \OCP\USER::getUser() .'/'.\OCP\Config::getSystemValue('files_versionsfolder', Storage::DEFAULTFOLDER); - if(!is_dir($foldername)){ - mkdir($foldername); - } - } - } - - - /** - * listen to write event. - */ - public static function write_hook($params) { - if(\OCP\Config::getSystemValue('files_versions', Storage::DEFAULTENABLED)=='true') { - $path = $params[\OC_Filesystem::signal_param_path]; - if($path<>'') Storage::store($path); - } - } - - - - /** - * store a new version of a file. - */ - public static function store($filename) { - if(\OCP\Config::getSystemValue('files_versions', Storage::DEFAULTENABLED)=='true') { - if (\OCP\App::isEnabled('files_sharing') && $source = \OC_Share::getSource('/'.\OCP\User::getUser().'/files'.$filename)) { - $pos = strpos($source, '/files', 1); - $uid = substr($source, 1, $pos - 1); - $filename = substr($source, $pos + 6); - } else { - $uid = \OCP\User::getUser(); - } - $versionsFolderName=\OCP\Config::getSystemValue('datadirectory').'/'. $uid .'/'.\OCP\Config::getSystemValue('files_versionsfolder', Storage::DEFAULTFOLDER); - $filesfoldername=\OCP\Config::getSystemValue('datadirectory').'/'. $uid .'/files'; - Storage::init(); - - // check if filename is a directory - if(is_dir($filesfoldername.'/'.$filename)){ - return false; - } - - // check filetype blacklist - $blacklist=explode(' ',\OCP\Config::getSystemValue('files_versionsblacklist', Storage::DEFAULTBLACKLIST)); - foreach($blacklist as $bl) { - $parts=explode('.', $filename); - $ext=end($parts); - if(strtolower($ext)==$bl) { - return false; - } - } - - // check filesize - if(filesize($filesfoldername.'/'.$filename)>\OCP\Config::getSystemValue('files_versionsmaxfilesize', Storage::DEFAULTMAXFILESIZE)){ - return false; - } - - - // check mininterval if the file is being modified by the owner (all shared files should be versioned despite mininterval) - if ($uid == \OCP\User::getUser()) { - $matches=glob($versionsFolderName.'/'.$filename.'.v*'); - sort($matches); - $parts=explode('.v',end($matches)); - if((end($parts)+Storage::DEFAULTMININTERVAL)>time()){ - return false; - } - } - - - // create all parent folders - $info=pathinfo($filename); - if(!file_exists($versionsFolderName.'/'.$info['dirname'])) mkdir($versionsFolderName.'/'.$info['dirname'],0700,true); - - // store a new version of a file - copy($filesfoldername.'/'.$filename,$versionsFolderName.'/'.$filename.'.v'.time()); - - // expire old revisions if necessary - Storage::expire($filename); - } - } - - - /** - * rollback to an old version of a file. - */ - public static function rollback($filename,$revision) { - - if(\OCP\Config::getSystemValue('files_versions', Storage::DEFAULTENABLED)=='true') { - if (\OCP\App::isEnabled('files_sharing') && $source = \OC_Share::getSource('/'.\OCP\User::getUser().'/files'.$filename)) { - $pos = strpos($source, '/files', 1); - $uid = substr($source, 1, $pos - 1); - $filename = substr($source, $pos + 6); - } else { - $uid = \OCP\User::getUser(); - } - $versionsFolderName=\OCP\Config::getSystemValue('datadirectory').'/'.$uid .'/'.\OCP\Config::getSystemValue('files_versionsfolder', Storage::DEFAULTFOLDER); - - $filesfoldername=\OCP\Config::getSystemValue('datadirectory').'/'. $uid .'/files'; - - // rollback - if ( @copy($versionsFolderName.'/'.$filename.'.v'.$revision,$filesfoldername.'/'.$filename) ) { - - return true; - - }else{ - - return false; - - } - - } - - } - - /** - * check if old versions of a file exist. - */ - public static function isversioned($filename) { - if(\OCP\Config::getSystemValue('files_versions', Storage::DEFAULTENABLED)=='true') { - if (\OCP\App::isEnabled('files_sharing') && $source = \OC_Share::getSource('/'.\OCP\User::getUser().'/files'.$filename)) { - $pos = strpos($source, '/files', 1); - $uid = substr($source, 1, $pos - 1); - $filename = substr($source, $pos + 6); - } else { - $uid = \OCP\User::getUser(); - } - $versionsFolderName=\OCP\Config::getSystemValue('datadirectory').'/'. $uid .'/'.\OCP\Config::getSystemValue('files_versionsfolder', Storage::DEFAULTFOLDER); - - // check for old versions - $matches=glob($versionsFolderName.'/'.$filename.'.v*'); - if(count($matches)>1){ - return true; - }else{ - return false; - } - }else{ - return(false); - } - } - - - - /** - * @brief get a list of all available versions of a file in descending chronological order - * @param $filename file to find versions of, relative to the user files dir - * @param $count number of versions to return - * @returns array - */ - public static function getVersions( $filename, $count = 0 ) { - - if( \OCP\Config::getSystemValue('files_versions', Storage::DEFAULTENABLED)=='true' ) { - - if (\OCP\App::isEnabled('files_sharing') && $source = \OC_Share::getSource('/'.\OCP\User::getUser().'/files'.$filename)) { - $pos = strpos($source, '/files', 1); - $uid = substr($source, 1, $pos - 1); - $filename = substr($source, $pos + 6); - } else { - $uid = \OCP\User::getUser(); - } - $versionsFolderName = \OCP\Config::getSystemValue('datadirectory').'/'. $uid .'/'.\OCP\Config::getSystemValue('files_versionsfolder', Storage::DEFAULTFOLDER); - $versions = array(); - - // fetch for old versions - $matches = glob( $versionsFolderName.'/'.$filename.'.v*' ); - - sort( $matches ); - - $i = 0; - - foreach( $matches as $ma ) { - - $i++; - $versions[$i]['cur'] = 0; - $parts = explode( '.v', $ma ); - $versions[$i]['version'] = ( end( $parts ) ); - - // if file with modified date exists, flag it in array as currently enabled version - $curFile['fileName'] = basename( $parts[0] ); - $curFile['filePath'] = \OCP\Config::getSystemValue('datadirectory').\OC_Filesystem::getRoot().'/'.$curFile['fileName']; - - ( \md5_file( $ma ) == \md5_file( $curFile['filePath'] ) ? $versions[$i]['fileMatch'] = 1 : $versions[$i]['fileMatch'] = 0 ); - - } - - $versions = array_reverse( $versions ); - - foreach( $versions as $key => $value ) { - - // flag the first matched file in array (which will have latest modification date) as current version - if ( $versions[$key]['fileMatch'] ) { - - $versions[$key]['cur'] = 1; - break; - - } - - } - - $versions = array_reverse( $versions ); - - // only show the newest commits - if( $count != 0 and ( count( $versions )>$count ) ) { - - $versions = array_slice( $versions, count( $versions ) - $count ); - - } - - return( $versions ); - - - } else { - - // if versioning isn't enabled then return an empty array - return( array() ); - - } - - } - - /** - * @brief Erase a file's versions which exceed the set quota - */ - public static function expire($filename) { - if(\OCP\Config::getSystemValue('files_versions', Storage::DEFAULTENABLED)=='true') { - - if (\OCP\App::isEnabled('files_sharing') && $source = \OC_Share::getSource('/'.\OCP\User::getUser().'/files'.$filename)) { - $pos = strpos($source, '/files', 1); - $uid = substr($source, 1, $pos - 1); - $filename = substr($source, $pos + 6); - } else { - $uid = \OCP\User::getUser(); - } - $versionsFolderName=\OCP\Config::getSystemValue('datadirectory').'/'. $uid .'/'.\OCP\Config::getSystemValue('files_versionsfolder', Storage::DEFAULTFOLDER); - - // check for old versions - $matches = glob( $versionsFolderName.'/'.$filename.'.v*' ); - - if( count( $matches ) > \OCP\Config::getSystemValue( 'files_versionmaxversions', Storage::DEFAULTMAXVERSIONS ) ) { - - $numberToDelete = count( $matches-\OCP\Config::getSystemValue( 'files_versionmaxversions', Storage::DEFAULTMAXVERSIONS ) ); - - // delete old versions of a file - $deleteItems = array_slice( $matches, 0, $numberToDelete ); - - foreach( $deleteItems as $de ) { - - unlink( $versionsFolderName.'/'.$filename.'.v'.$de ); - - } - } - } - } - - /** - * @brief Erase all old versions of all user files - * @return true/false - */ - public static function expireAll() { - - $view = new \OC_FilesystemView(''); - - $dir = \OCP\Config::getSystemValue('files_versionsfolder', Storage::DEFAULTFOLDER); - - return $view->deleteAll( $dir, true ); - - } - - -} +<?php +/** + * Copyright (c) 2012 Frank Karlitschek <frank@owncloud.org> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +/** + * Versions + * + * A class to handle the versioning of files. + */ + +namespace OCA_Versions; + +class Storage { + + + // config.php configuration: + // - files_versions + // - files_versionsfolder + // - files_versionsblacklist + // - files_versionsmaxfilesize + // - files_versionsinterval + // - files_versionmaxversions + // + // todo: + // - finish porting to OC_FilesystemView to enable network transparency + // - add transparent compression. first test if it´s worth it. + + const DEFAULTENABLED=true; + const DEFAULTFOLDER='versions'; + const DEFAULTBLACKLIST='avi mp3 mpg mp4 ctmp'; + const DEFAULTMAXFILESIZE=1048576; // 10MB + const DEFAULTMININTERVAL=1; // 2 min + const DEFAULTMAXVERSIONS=50; + + private $view; + + function __construct( $view ) { + + $this->view = $view; + + } + + /** + * init the versioning and create the versions folder. + */ + public static function init() { + if(\OCP\Config::getSystemValue('files_versions', Storage::DEFAULTENABLED)=='true') { + // create versions folder + $foldername=\OCP\Config::getSystemValue('datadirectory').'/'. \OCP\USER::getUser() .'/'.\OCP\Config::getSystemValue('files_versionsfolder', Storage::DEFAULTFOLDER); + if(!is_dir($foldername)){ + mkdir($foldername); + } + } + } + + + /** + * listen to write event. + */ + public static function write_hook($params) { + if(\OCP\Config::getSystemValue('files_versions', Storage::DEFAULTENABLED)=='true') { + $path = $params[\OC_Filesystem::signal_param_path]; + if($path<>'') $this->store($path); + } + } + + + + /** + * store a new version of a file. + */ + public function store($filename) { + if(\OCP\Config::getSystemValue('files_versions', Storage::DEFAULTENABLED)=='true') { + + $files_view = \OCP\Files::getStorage("files"); + $users_view = \OCP\Files::getStorage("files_versions"); + $users_view->chroot(\OCP\User::getUser().'/'); + + if (\OCP\App::isEnabled('files_sharing') && $source = \OC_Share::getSource('/'.\OCP\User::getUser().'/files'.$filename)) { + $pos = strpos($source, '/files', 1); + $uid = substr($source, 1, $pos - 1); + $filename = substr($source, $pos + 6); + } else { + $uid = \OCP\User::getUser(); + } + $versionsFolderName=\OCP\Config::getSystemValue('datadirectory').'/'. $uid .'/'.\OCP\Config::getSystemValue('files_versionsfolder', Storage::DEFAULTFOLDER); + $filesfoldername=\OCP\Config::getSystemValue('datadirectory').'/'. $uid .'/files'; + Storage::init(); + + //check if source file already exist as version to avoid recursions. + if ($users_view->file_exists($filename)) { + return false; + } + + // check if filename is a directory + if($files_view->is_dir($filename)){ + return false; + } + + // check filetype blacklist + $blacklist=explode(' ',\OCP\Config::getSystemValue('files_versionsblacklist', Storage::DEFAULTBLACKLIST)); + foreach($blacklist as $bl) { + $parts=explode('.', $filename); + $ext=end($parts); + if(strtolower($ext)==$bl) { + return false; + } + } + + // check filesize + if($files_view->filesize($filename)>\OCP\Config::getSystemValue('files_versionsmaxfilesize', Storage::DEFAULTMAXFILESIZE)){ + return false; + } + + + // check mininterval if the file is being modified by the owner (all shared files should be versioned despite mininterval) + if ($uid == \OCP\User::getUser()) { + $matches=glob($versionsFolderName.'/'.$filename.'.v*'); + sort($matches); + $parts=explode('.v',end($matches)); + if((end($parts)+Storage::DEFAULTMININTERVAL)>time()){ + return false; + } + } + + + // create all parent folders + $info=pathinfo($filename); + if(!file_exists($versionsFolderName.'/'.$info['dirname'])) mkdir($versionsFolderName.'/'.$info['dirname'],0700,true); + + // store a new version of a file + @$users_view->copy('files'.$filename, 'versions'.$filename.'.v'.time()); + + // expire old revisions if necessary + Storage::expire($filename); + } + } + + + /** + * rollback to an old version of a file. + */ + public static function rollback($filename,$revision) { + + if(\OCP\Config::getSystemValue('files_versions', Storage::DEFAULTENABLED)=='true') { + if (\OCP\App::isEnabled('files_sharing') && $source = \OC_Share::getSource('/'.\OCP\User::getUser().'/files'.$filename)) { + $pos = strpos($source, '/files', 1); + $uid = substr($source, 1, $pos - 1); + $filename = substr($source, $pos + 6); + } else { + $uid = \OCP\User::getUser(); + } + $versionsFolderName=\OCP\Config::getSystemValue('datadirectory').'/'.$uid .'/'.\OCP\Config::getSystemValue('files_versionsfolder', Storage::DEFAULTFOLDER); + + $filesfoldername=\OCP\Config::getSystemValue('datadirectory').'/'. $uid .'/files'; + + // rollback + if ( @copy($versionsFolderName.'/'.$filename.'.v'.$revision,$filesfoldername.'/'.$filename) ) { + + return true; + + }else{ + + return false; + + } + + } + + } + + /** + * check if old versions of a file exist. + */ + public static function isversioned($filename) { + if(\OCP\Config::getSystemValue('files_versions', Storage::DEFAULTENABLED)=='true') { + if (\OCP\App::isEnabled('files_sharing') && $source = \OC_Share::getSource('/'.\OCP\User::getUser().'/files'.$filename)) { + $pos = strpos($source, '/files', 1); + $uid = substr($source, 1, $pos - 1); + $filename = substr($source, $pos + 6); + } else { + $uid = \OCP\User::getUser(); + } + $versionsFolderName=\OCP\Config::getSystemValue('datadirectory').'/'. $uid .'/'.\OCP\Config::getSystemValue('files_versionsfolder', Storage::DEFAULTFOLDER); + + // check for old versions + $matches=glob($versionsFolderName.'/'.$filename.'.v*'); + if(count($matches)>1){ + return true; + }else{ + return false; + } + }else{ + return(false); + } + } + + + + /** + * @brief get a list of all available versions of a file in descending chronological order + * @param $filename file to find versions of, relative to the user files dir + * @param $count number of versions to return + * @returns array + */ + public static function getVersions( $filename, $count = 0 ) { + + if( \OCP\Config::getSystemValue('files_versions', Storage::DEFAULTENABLED)=='true' ) { + + if (\OCP\App::isEnabled('files_sharing') && $source = \OC_Share::getSource('/'.\OCP\User::getUser().'/files'.$filename)) { + $pos = strpos($source, '/files', 1); + $uid = substr($source, 1, $pos - 1); + $filename = substr($source, $pos + 6); + } else { + $uid = \OCP\User::getUser(); + } + $versionsFolderName = \OCP\Config::getSystemValue('datadirectory').'/'. $uid .'/'.\OCP\Config::getSystemValue('files_versionsfolder', Storage::DEFAULTFOLDER); + $versions = array(); + + // fetch for old versions + $matches = glob( $versionsFolderName.'/'.$filename.'.v*' ); + + sort( $matches ); + + $i = 0; + + foreach( $matches as $ma ) { + + $i++; + $versions[$i]['cur'] = 0; + $parts = explode( '.v', $ma ); + $versions[$i]['version'] = ( end( $parts ) ); + + // if file with modified date exists, flag it in array as currently enabled version + $curFile['fileName'] = basename( $parts[0] ); + $curFile['filePath'] = \OCP\Config::getSystemValue('datadirectory').\OC_Filesystem::getRoot().'/'.$curFile['fileName']; + + ( \md5_file( $ma ) == \md5_file( $curFile['filePath'] ) ? $versions[$i]['fileMatch'] = 1 : $versions[$i]['fileMatch'] = 0 ); + + } + + $versions = array_reverse( $versions ); + + foreach( $versions as $key => $value ) { + + // flag the first matched file in array (which will have latest modification date) as current version + if ( $versions[$key]['fileMatch'] ) { + + $versions[$key]['cur'] = 1; + break; + + } + + } + + $versions = array_reverse( $versions ); + + // only show the newest commits + if( $count != 0 and ( count( $versions )>$count ) ) { + + $versions = array_slice( $versions, count( $versions ) - $count ); + + } + + return( $versions ); + + + } else { + + // if versioning isn't enabled then return an empty array + return( array() ); + + } + + } + + /** + * @brief Erase a file's versions which exceed the set quota + */ + public static function expire($filename) { + if(\OCP\Config::getSystemValue('files_versions', Storage::DEFAULTENABLED)=='true') { + + if (\OCP\App::isEnabled('files_sharing') && $source = \OC_Share::getSource('/'.\OCP\User::getUser().'/files'.$filename)) { + $pos = strpos($source, '/files', 1); + $uid = substr($source, 1, $pos - 1); + $filename = substr($source, $pos + 6); + } else { + $uid = \OCP\User::getUser(); + } + $versionsFolderName=\OCP\Config::getSystemValue('datadirectory').'/'. $uid .'/'.\OCP\Config::getSystemValue('files_versionsfolder', Storage::DEFAULTFOLDER); + + // check for old versions + $matches = glob( $versionsFolderName.'/'.$filename.'.v*' ); + + if( count( $matches ) > \OCP\Config::getSystemValue( 'files_versionmaxversions', Storage::DEFAULTMAXVERSIONS ) ) { + + $numberToDelete = count( $matches-\OCP\Config::getSystemValue( 'files_versionmaxversions', Storage::DEFAULTMAXVERSIONS ) ); + + // delete old versions of a file + $deleteItems = array_slice( $matches, 0, $numberToDelete ); + + foreach( $deleteItems as $de ) { + + unlink( $versionsFolderName.'/'.$filename.'.v'.$de ); + + } + } + } + } + + /** + * @brief Erase all old versions of all user files + * @return true/false + */ + public function expireAll() { + + $dir = \OCP\Config::getSystemValue('files_versionsfolder', Storage::DEFAULTFOLDER); + + return $this->view->deleteAll( $dir, true ); + + } + + /** + * @brief Erase versions of deleted file + * @param array + * + * This function is connected to the delete signal of OC_Filesystem + * cleanup the versions directory if the actual file gets deleted + */ + public static function removeVersions($params) { + $rel_path = $params['path']; + $abs_path = \OCP\Config::getSystemValue('datadirectory').'/'.\OCP\User::getUser()."/versions".$rel_path.'.v'; + if(Storage::isversioned($rel_path)) { + $versions = Storage::getVersions($rel_path); + foreach ($versions as $v){ + unlink($abs_path . $v['version']); + } + } + } + + /** + * @brief rename/move versions of renamed/moved files + * @param array with oldpath and newpath + * + * This function is connected to the rename signal of OC_Filesystem and adjust the name and location + * of the stored versions along the actual file + */ + public static function renameVersions($params) { + $rel_oldpath = $params['oldpath']; + $abs_oldpath = \OCP\Config::getSystemValue('datadirectory').'/'.\OCP\User::getUser()."/versions".$rel_oldpath.'.v'; + $abs_newpath = \OCP\Config::getSystemValue('datadirectory').'/'.\OCP\User::getUser()."/versions".$params['newpath'].'.v'; + if(Storage::isversioned($rel_oldpath)) { + $versions = Storage::getVersions($rel_oldpath); + foreach ($versions as $v){ + rename($abs_oldpath.$v['version'], $abs_newpath.$v['version']); + } + } + } +} diff --git a/apps/files_versions/templates/history.php b/apps/files_versions/templates/history.php index 13e104152b7cffcf0aa1e66446e229ab1a70d150..1b4425564212ebddec4e6f1ca82334b3159d8596 100644 --- a/apps/files_versions/templates/history.php +++ b/apps/files_versions/templates/history.php @@ -20,13 +20,11 @@ if( isset( $_['message'] ) ) { echo('<p><em>Revert a file to a previous version by clicking on its revert button</em></p><br />'); foreach ( $_['versions'] as $v ) { - echo ' '; - echo OCP\Util::formatDate( $v['version'] ); + echo OCP\Util::formatDate( doubleval($v['version']) ); echo ' <a href="'.OCP\Util::linkTo('files_versions', 'history.php').'?path='.urlencode( $_['path'] ).'&revert='. $v['version'] .'" class="button">Revert</a><br /><br />'; if ( $v['cur'] ) { echo ' (<b>Current</b>)'; } echo '<br /><br />'; - } } diff --git a/apps/gallery/lib/managers.php b/apps/gallery/lib/managers.php index fcce3f40e23d673b7db22adef3e62880a141dace..17eb741a660e0accfe2dcd2cd199ee17b589d197 100644 --- a/apps/gallery/lib/managers.php +++ b/apps/gallery/lib/managers.php @@ -4,6 +4,7 @@ namespace OC\Pictures; class DatabaseManager { private static $instance = null; + protected $cache = array(); const TAG = 'DatabaseManager'; public static function getInstance() { @@ -12,13 +13,27 @@ class DatabaseManager { return self::$instance; } + protected function getPathData($path) { + $stmt = \OCP\DB::prepare('SELECT * FROM *PREFIX*pictures_images_cache + WHERE uid_owner LIKE ? AND path like ? AND path not like ?'); + $path_match = $path.'/%'; + $path_notmatch = $path.'/%/%'; + $result = $stmt->execute(array(\OCP\USER::getUser(), $path_match, $path_notmatch)); + $this->cache[$path] = array(); + while (($row = $result->fetchRow()) != false) { + $this->cache[$path][$row['path']] = $row; + } + } + public function getFileData($path) { $gallery_path = \OCP\Config::getSystemValue( 'datadirectory' ).'/'.\OC_User::getUser().'/gallery'; $path = $gallery_path.$path; - $stmt = \OCP\DB::prepare('SELECT * FROM *PREFIX*pictures_images_cache WHERE uid_owner LIKE ? AND path = ?'); - $result = $stmt->execute(array(\OCP\USER::getUser(), $path)); - if (($row = $result->fetchRow()) != false) { - return $row; + $dir = dirname($path); + if (!isset($this->cache[$dir])) { + $this->getPathData($dir); + } + if (isset($this->cache[$dir][$path])) { + return $this->cache[$dir][$path]; } $image = new \OC_Image(); if (!$image->loadFromFile($path)) { @@ -28,6 +43,7 @@ class DatabaseManager { $stmt->execute(array(\OCP\USER::getUser(), $path, $image->width(), $image->height())); $ret = array('path' => $path, 'width' => $image->width(), 'height' => $image->height()); unset($image); + $this->cache[$dir][$path] = $ret; return $ret; } diff --git a/apps/user_ldap/appinfo/update.php b/apps/user_ldap/appinfo/update.php index dc437ce21ce90f1b416889f98374b71611158bc7..badceb378d1876e88b9089cda8955102ee97dee2 100644 --- a/apps/user_ldap/appinfo/update.php +++ b/apps/user_ldap/appinfo/update.php @@ -31,3 +31,21 @@ if($state == 'doCheck'){ OCP\Config::setSystemValue('ldapIgnoreNamingRules', true); } } + + +//from version 0.2 to 0.2.1 +$objects = array('user', 'group'); + +foreach($objects as $object) { + $fetchDNSql = 'SELECT ldap_dn from *PREFIX*ldap_'.$object.'_mapping'; + $updateSql = 'UPDATE *PREFIX*ldap_'.$object.'_mapping SET ldap_DN = ? WHERE ldap_dn = ?'; + + $query = OCP\DB::prepare($fetchDNSql); + $res = $query->execute(); + $DNs = $res->fetchAll(); + $updateQuery = OCP\DB::prepare($updateSql); + foreach($DNs as $dn) { + $newDN = mb_strtolower($dn['ldap_dn'], 'UTF-8'); + $updateQuery->execute(array($newDN, $dn['ldap_dn'])); + } +} diff --git a/apps/user_ldap/appinfo/version b/apps/user_ldap/appinfo/version index 2f4536184bcac31936bd15a5f9cf931dd526c022..5f021e960ec5764d916dc36434176c96a7346229 100644 --- a/apps/user_ldap/appinfo/version +++ b/apps/user_ldap/appinfo/version @@ -1 +1 @@ -0.2 \ No newline at end of file +0.2.0.5 \ No newline at end of file diff --git a/apps/user_ldap/group_ldap.php b/apps/user_ldap/group_ldap.php index a3117b5a41e5a7711c8c0a6c32a9e2f26a955568..d438c7d84dfa6b29e98ef87b54f93d7fb368a334 100644 --- a/apps/user_ldap/group_ldap.php +++ b/apps/user_ldap/group_ldap.php @@ -158,7 +158,7 @@ class OC_GROUP_LDAP extends OC_Group_Backend { $isMemberUid = (strtolower($this->ldapGroupMemberAssocAttr) == 'memberuid'); foreach($members as $member) { if($isMemberUid) { - $filter = str_replace('%uid', $member, OC_LDAP::conf('ldapLoginFilter')); + $filter = OCP\Util::mb_str_replace('%uid', $member, OC_LDAP::conf('ldapLoginFilter'), 'UTF-8'); $ldap_users = OC_LDAP::fetchListOfUsers($filter, 'dn'); if(count($ldap_users) < 1) { continue; diff --git a/apps/user_ldap/lib_ldap.php b/apps/user_ldap/lib_ldap.php index 21c4e57e2933eacbbd2763a6c6995989b09fddcd..08b09304d780cd224e680010011582a05f131aaa 100644 --- a/apps/user_ldap/lib_ldap.php +++ b/apps/user_ldap/lib_ldap.php @@ -171,7 +171,7 @@ class OC_LDAP { * returns the internal ownCloud name for the given LDAP DN of the group */ static public function dn2groupname($dn, $ldapname = null) { - if(strripos($dn, self::$ldapBaseGroups) !== (strlen($dn)-strlen(self::$ldapBaseGroups))) { + if(mb_strripos($dn, self::$ldapBaseGroups, 0, 'UTF-8') !== (mb_strlen($dn, 'UTF-8')-mb_strlen(self::$ldapBaseGroups, 'UTF-8'))) { return false; } return self::dn2ocname($dn, $ldapname, false); @@ -186,7 +186,7 @@ class OC_LDAP { * returns the internal ownCloud name for the given LDAP DN of the user, false on DN outside of search DN */ static public function dn2username($dn, $ldapname = null) { - if(strripos($dn, self::$ldapBaseUsers) !== (strlen($dn)-strlen(self::$ldapBaseUsers))) { + if(mb_strripos($dn, self::$ldapBaseUsers, 0, 'UTF-8') !== (mb_strlen($dn, 'UTF-8')-mb_strlen(self::$ldapBaseUsers, 'UTF-8'))) { return false; } return self::dn2ocname($dn, $ldapname, true); @@ -304,7 +304,7 @@ class OC_LDAP { */ static private function alternateOwnCloudName($name, $dn) { $ufn = ldap_dn2ufn($dn); - $name = $name . '@' . trim(substr_replace($ufn, '', 0, strpos($ufn, ','))); + $name = $name . '@' . trim(OCP\Util::mb_substr_replace($ufn, '', 0, mb_strpos($ufn, ',', 0, 'UTF-8'), 'UTF-8')); $name = self::sanitizeUsername($name); return $name; } @@ -419,8 +419,8 @@ class OC_LDAP { $rr = ldap_read($cr, $dn, 'objectClass=*', array($attr)); $er = ldap_first_entry($cr, $rr); //LDAP attributes are not case sensitive - $result = array_change_key_case(ldap_get_attributes($cr, $er)); - $attr = strtolower($attr); + $result = OCP\Util::mb_array_change_key_case(ldap_get_attributes($cr, $er), MB_CASE_LOWER, 'UTF-8'); + $attr = mb_strtolower($attr, 'UTF-8'); if(isset($result[$attr]) && $result[$attr]['count'] > 0){ $values = array(); @@ -469,22 +469,21 @@ class OC_LDAP { */ static private function search($filter, $base, $attr = null) { if(!is_null($attr) && !is_array($attr)) { - $attr = array(strtolower($attr)); + $attr = array(mb_strtolower($attr, 'UTF-8')); } // See if we have a resource $link_resource = self::getConnectionResource(); - if($link_resource) - { + if(is_resource($link_resource)) { $sr = ldap_search($link_resource, $base, $filter, $attr); $findings = ldap_get_entries($link_resource, $sr ); + // if we're here, probably no connection resource is returned. // to make ownCloud behave nicely, we simply give back an empty array. if(is_null($findings)) { return array(); } - } else - { + } else { // Seems like we didn't find any resource. // Return an empty array just like before. return array(); @@ -501,11 +500,11 @@ class OC_LDAP { if(!is_array($item)) { continue; } - $item = array_change_key_case($item); + $item = OCP\Util::mb_array_change_key_case($item, MB_CASE_LOWER, 'UTF-8'); if($multiarray) { foreach($attr as $key) { - $key = strtolower($key); + $key = mb_strtolower($key, 'UTF-8'); if(isset($item[$key])) { if($key != 'dn'){ $selection[$i][$key] = self::resemblesDN($key) ? self::sanitizeDN($item[$key][0]) : $item[$key][0]; @@ -518,7 +517,7 @@ class OC_LDAP { $i++; } else { //tribute to case insensitivity - $key = strtolower($attr[0]); + $key = mb_strtolower($attr[0], 'UTF-8'); if(isset($item[$key])) { if(self::resemblesDN($key)) { @@ -547,10 +546,10 @@ class OC_LDAP { static private function sanitizeDN($dn) { //OID sometimes gives back DNs with whitespace after the comma a la "uid=foo, cn=bar, dn=..." We need to tackle this! - $dn = preg_replace('/([^\\\]),(\s+)/','\1,',$dn); + $dn = preg_replace('/([^\\\]),(\s+)/u','\1,',$dn); //make comparisons and everything work - $dn = strtolower($dn); + $dn = mb_strtolower($dn, 'UTF-8'); return $dn; } @@ -561,10 +560,10 @@ class OC_LDAP { } //REPLACEMENTS - $name = str_replace(' ', '_', $name); + $name = OCP\Util::mb_str_replace(' ', '_', $name, 'UTF-8'); //every remaining unallowed characters will be removed - $name = preg_replace('/[^a-zA-Z0-9_.@-]/', '', $name); + $name = preg_replace('/[^a-zA-Z0-9_.@-]/u', '', $name); return $name; } @@ -638,10 +637,10 @@ class OC_LDAP { self::$ldapBaseGroups = OCP\Config::getAppValue('user_ldap', 'ldap_base_groups', self::$ldapBase); self::$ldapTLS = OCP\Config::getAppValue('user_ldap', 'ldap_tls',0); self::$ldapNoCase = OCP\Config::getAppValue('user_ldap', 'ldap_nocase', 0); - self::$ldapUserDisplayName = strtolower(OCP\Config::getAppValue('user_ldap', 'ldap_display_name', 'uid')); + self::$ldapUserDisplayName = mb_strtolower(OCP\Config::getAppValue('user_ldap', 'ldap_display_name', 'uid'), 'UTF-8'); self::$ldapUserFilter = OCP\Config::getAppValue('user_ldap', 'ldap_userlist_filter','objectClass=person'); self::$ldapLoginFilter = OCP\Config::getAppValue('user_ldap', 'ldap_login_filter', '(uid=%uid)'); - self::$ldapGroupDisplayName = strtolower(OCP\Config::getAppValue('user_ldap', 'ldap_group_display_name', LDAP_GROUP_DISPLAY_NAME_ATTR)); + self::$ldapGroupDisplayName = mb_strtolower(OCP\Config::getAppValue('user_ldap', 'ldap_group_display_name', LDAP_GROUP_DISPLAY_NAME_ATTR), 'UTF-8'); self::$ldapIgnoreNamingRules = OCP\Config::getSystemValue('ldapIgnoreNamingRules', false); if(empty(self::$ldapBaseUsers)) { @@ -690,6 +689,7 @@ class OC_LDAP { $ldapLogin = @ldap_bind(self::$ldapConnectionRes, self::$ldapAgentName, self::$ldapAgentPassword ); if(!$ldapLogin) { OCP\Util::writeLog('ldap', 'Bind failed: ' . ldap_errno(self::$ldapConnectionRes) . ': ' . ldap_error(self::$ldapConnectionRes), OCP\Util::ERROR); + self::$ldapConnectionRes = null; return false; } } diff --git a/apps/user_ldap/user_ldap.php b/apps/user_ldap/user_ldap.php index 85b3d88973c7d4e2d528e6b63322e6f6e086c100..b51d9a55cc79466ee892fddf69d92eecf0aecc7e 100644 --- a/apps/user_ldap/user_ldap.php +++ b/apps/user_ldap/user_ldap.php @@ -84,7 +84,7 @@ class OC_USER_LDAP extends OC_User_Backend { */ public function checkPassword($uid, $password){ //find out dn of the user name - $filter = str_replace('%uid', $uid, OC_LDAP::conf('ldapLoginFilter')); + $filter = OCP\Util::mb_str_replace('%uid', $uid, OC_LDAP::conf('ldapLoginFilter'), 'UTF-8'); $ldap_users = OC_LDAP::fetchListOfUsers($filter, 'dn'); if(count($ldap_users) < 1) { return false; diff --git a/apps/user_openid/appinfo/app.php b/apps/user_openid/appinfo/app.php index c683254101fde20a054ed98b8bd66e49746b1571..fe57b189fac3a97205274ba06222f15f345b230a 100644 --- a/apps/user_openid/appinfo/app.php +++ b/apps/user_openid/appinfo/app.php @@ -27,7 +27,7 @@ OC_User::useBackend('openid'); //check for results from openid requests if(isset($_GET['openid_mode']) and $_GET['openid_mode'] == 'id_res'){ OCP\Util::writeLog('user_openid','openid retured',OCP\Util::DEBUG); - $openid = new SimpleOpenID; + $openid = new SimpleOpenID(); $openid->SetIdentity($_GET['openid_identity']); $openid_validation_result = $openid->ValidateWithServer(); if ($openid_validation_result == true){ // OK HERE KEY IS VALID @@ -50,5 +50,3 @@ if(isset($_GET['openid_mode']) and $_GET['openid_mode'] == 'id_res'){ OCP\Util::writeLog('user_openid','USER CANCELED REQUEST',OCP\Util::DEBUG); return false; } - -?> diff --git a/apps/user_openid/appinfo/version b/apps/user_openid/appinfo/version index 6da28dde76d6550e3d398a70a9a8231256774669..d917d3e26adc9854b4569871e20111c38de2606f 100644 --- a/apps/user_openid/appinfo/version +++ b/apps/user_openid/appinfo/version @@ -1 +1 @@ -0.1.1 \ No newline at end of file +0.1.2 diff --git a/apps/user_openid/class.openid.v3.php b/apps/user_openid/class.openid.v3.php index 8afb9e5b8175be25c28ed43aea6f8690250cd1cd..eeb319866598c8312faff2a3242d7d8cbd22495f 100644 --- a/apps/user_openid/class.openid.v3.php +++ b/apps/user_openid/class.openid.v3.php @@ -324,5 +324,3 @@ class SimpleOpenID{ } } } - -?> \ No newline at end of file diff --git a/apps/user_openid/user_openid.php b/apps/user_openid/user_openid.php index e228de95e9e570e14a919083f3e4189ceb573b18..70b193a30b13cf8b61b174f3501ad021d46fab65 100644 --- a/apps/user_openid/user_openid.php +++ b/apps/user_openid/user_openid.php @@ -37,7 +37,7 @@ class OC_USER_OPENID extends OC_User_Backend { */ public function checkPassword( $uid, $password ){ // Get identity from user and redirect browser to OpenID Server - $openid = new SimpleOpenID; + $openid = new SimpleOpenID(); $openid->SetIdentity($uid); $openid->SetTrustRoot('http://' . OCP\Util::getServerHost()); if ($openid->GetOpenIDServer()){ @@ -63,7 +63,3 @@ class OC_USER_OPENID extends OC_User_Backend { } } } - - - -?> diff --git a/core/js/js.js b/core/js/js.js index 7a53bb75ef5ec871d3c22b72814a4fc838aeca0a..d6483b2c22561617343b40ff5e1a7eaa1b8462db 100644 --- a/core/js/js.js +++ b/core/js/js.js @@ -67,6 +67,8 @@ OC={ if(type){ link+= '/'+type+'/'; } + if(link.substring(link.length-1) != '/') + link+='/'; link+=file; }else{ link+='/'; diff --git a/core/js/multiselect.js b/core/js/multiselect.js index db5afa637c94de4a50318b9b9de5d6064a70ae15..c4fd74b0475e746844b554f23d9b94f487de8b45 100644 --- a/core/js/multiselect.js +++ b/core/js/multiselect.js @@ -35,6 +35,7 @@ } button.click(function(event){ + var button=$(this); if(button.parent().children('ul').length>0){ button.parent().children('ul').slideUp(400,function(){ @@ -128,19 +129,30 @@ if(event.keyCode == 13) { event.preventDefault(); event.stopPropagation(); + var value = $(this).val(); + var exists = false; + $.each(options,function(index, item) { + if ($(item).val() == value) { + exists = true; + return false; + } + }); + if (exists) { + return false; + } var li=$(this).parent(); $(this).remove(); li.text('+ '+settings.createText); li.before(createItem(this)); var select=button.parent().next(); var option=$('<option selected="selected"/>'); - option.attr('value',$(this).val()); + option.attr('value',value); option.text($(this).val()); - select.append(options); + select.append(option); li.prev().children('input').trigger('click'); button.parent().data('preventHide',false); if(settings.createCallback){ - settings.createCallback(); + settings.createCallback($(this).val()); } } }); diff --git a/lib/app.php b/lib/app.php index a9feff1620ab2f17a688fefdb3c779e3d9ac25dd..4c2c43ec26be72c97b1061d7b444e402e6396d0d 100755 --- a/lib/app.php +++ b/lib/app.php @@ -36,6 +36,7 @@ class OC_App{ static private $appInfo = array(); static private $appTypes = array(); static private $loadedApps = array(); + static private $checkedApps = array(); /** * @brief loads all apps @@ -349,9 +350,13 @@ class OC_App{ protected static function findAppInDirectories($appid) { + static $app_dir = array(); + if (isset($app_dir[$appid])) { + return $app_dir[$appid]; + } foreach(OC::$APPSROOTS as $dir) { if(file_exists($dir['path'].'/'.$appid)) { - return $dir; + return $app_dir[$appid]=$dir; } } } @@ -530,6 +535,10 @@ class OC_App{ * check if the app need updating and update when needed */ public static function checkUpgrade($app) { + if (in_array($app, self::$checkedApps)) { + return; + } + self::$checkedApps[] = $app; $versions = self::getAppVersions(); $currentVersion=OC_App::getAppVersion($app); if ($currentVersion) { @@ -564,7 +573,7 @@ class OC_App{ } /** - * get the installed version of all papps + * get the installed version of all apps */ public static function getAppVersions(){ static $versions; diff --git a/lib/base.php b/lib/base.php index c2b0bbef78020a0cbcbd9ec36ee63c6aa3fcc7d2..fe69ad70c0f1bb2b3cefd7387cb8837137079f83 100644 --- a/lib/base.php +++ b/lib/base.php @@ -330,21 +330,6 @@ class OC{ self::checkInstalled(); self::checkSSL(); - - // CSRF protection - if(isset($_SERVER['HTTP_REFERER'])) $referer=$_SERVER['HTTP_REFERER']; else $referer=''; - $refererhost=parse_url($referer); - if(isset($refererhost['host'])) $refererhost=$refererhost['host']; else $refererhost=''; - $server=OC_Helper::serverHost(); - $serverhost=explode(':',$server); - $serverhost=$serverhost['0']; - if(!self::$CLI){ - if(($_SERVER['REQUEST_METHOD']=='POST') and ($refererhost<>$serverhost)) { - $url = OC_Helper::serverProtocol().'://'.$server.OC::$WEBROOT.'/index.php'; - header("Location: $url"); - exit(); - } - } self::initSession(); self::initTemplateEngine(); self::checkUpgrade(); diff --git a/lib/db.php b/lib/db.php index 9e6835adc6ffd323d89b22e4721118bf2e159311..2a06d72ea323db8e4e0e53f168fe982335814523 100644 --- a/lib/db.php +++ b/lib/db.php @@ -128,6 +128,14 @@ class OC_DB { }else{ $dsn='pgsql:dbname='.$name.';host='.$host; } + /** + * Ugly fix for pg connections pbm when password use spaces + */ + $e_user = addslashes($user); + $e_password = addslashes($pass); + $pass = $user = null; + $dsn .= ";user='$e_user';password='$e_password'"; + /** END OF FIX***/ break; } try{ @@ -528,7 +536,7 @@ class OC_DB { self::removeDBStructure( OC::$SERVERROOT . '/db_structure.xml' ); foreach($apps as $app){ - $path = self::getAppPath($app).'/appinfo/database.xml'; + $path = OC_App::getAppPath($app).'/appinfo/database.xml'; if(file_exists($path)){ self::removeDBStructure( $path ); } diff --git a/lib/files.php b/lib/files.php index 469c3a15b8eb9ea69f8befc6b53f711303d74d6c..d5bebb7e549af13a2f59a7fba3bc0603aaff3ae8 100644 --- a/lib/files.php +++ b/lib/files.php @@ -167,10 +167,12 @@ class OC_Files { * @param file $target */ public static function move($sourceDir,$source,$targetDir,$target){ - if(OC_User::isLoggedIn() && ($sourceDir != '' || $source != 'Shared')){ + if(OC_User::isLoggedIn() && ($sourceDir != '' || $source != 'Shared') && !OC_Filesystem::file_exists($targetDir.'/'.$target)){ $targetFile=self::normalizePath($targetDir.'/'.$target); $sourceFile=self::normalizePath($sourceDir.'/'.$source); return OC_Filesystem::rename($sourceFile,$targetFile); + } else { + return false; } } diff --git a/lib/filesystem.php b/lib/filesystem.php index 0ab3bd69acd85836bf05dc30da853ba5a5782e50..65318fa3ab695214e52723d16aa289fa2610c19d 100644 --- a/lib/filesystem.php +++ b/lib/filesystem.php @@ -153,6 +153,7 @@ class OC_Filesystem{ if($path[0]!=='/'){ $path='/'.$path; } + $path=str_replace('//', '/',$path); $foundMountPoint=''; foreach(OC_Filesystem::$mounts as $mountpoint=>$storage){ if($mountpoint==$path){ diff --git a/lib/filesystemview.php b/lib/filesystemview.php index 99e08c50e75e92446f553b007ffd45fc30910165..448663bb0811b5906499d2c15a11ab910e343e69 100644 --- a/lib/filesystemview.php +++ b/lib/filesystemview.php @@ -276,7 +276,7 @@ class OC_FilesystemView { }else{ $source=$this->fopen($path1,'r'); $target=$this->fopen($path2,'w'); - $count=OC_Helper::streamCopy($data,$target); + $count=OC_Helper::streamCopy($source,$target); $storage1=$this->getStorage($path1); $storage1->unlink($this->getInternalPath($path1)); $result=$count>0; @@ -314,7 +314,7 @@ class OC_FilesystemView { }else{ $source=$this->fopen($path1,'r'); $target=$this->fopen($path2,'w'); - $count=OC_Helper::streamCopy($data,$target); + $result=OC_Helper::streamCopy($source,$target); } OC_Hook::emit( OC_Filesystem::CLASSNAME, OC_Filesystem::signal_post_copy, array( OC_Filesystem::signal_param_oldpath => $path1 , OC_Filesystem::signal_param_newpath=>$path2)); if(!$exists){ diff --git a/lib/helper.php b/lib/helper.php index 6ab55f27618154006faf1ca4d54cd7fa5cc77166..0d18098a4e756ce55d73a2c4a8d6f7f4d2e8cc85 100644 --- a/lib/helper.php +++ b/lib/helper.php @@ -38,21 +38,18 @@ class OC_Helper { */ public static function linkTo( $app, $file ){ if( $app != '' ){ - $app .= '/'; + $app_path = OC_App::getAppPath($app); // Check if the app is in the app folder - if( file_exists( OC_App::getAppPath($app).'/'.$file )){ - if(substr($file, -3) == 'php' || substr($file, -3) == 'css'){ - if(substr($app, -1, 1) == '/'){ - $app = substr($app, 0, strlen($app) - 1); - } + if( $app_path && file_exists( $app_path.'/'.$file )){ + if(substr($file, -3) == 'php' || substr($file, -3) == 'css'){ $urlLinkTo = OC::$WEBROOT . '/?app=' . $app; $urlLinkTo .= ($file!='index.php')?'&getfile=' . urlencode($file):''; }else{ - $urlLinkTo = OC_App::getAppWebPath($app) . $file; + $urlLinkTo = OC_App::getAppWebPath($app) . '/' . $file; } } else{ - $urlLinkTo = OC::$WEBROOT . '/' . $app . $file; + $urlLinkTo = OC::$WEBROOT . '/' . $app . '/' . $file; } } else{ @@ -382,7 +379,7 @@ class OC_Helper { //trim the character set from the end of the response $mimeType=substr($reply,0,strrpos($reply,' ')); - //trim ; + //trim ; if (strpos($mimeType, ';') !== false) { $mimeType = strstr($mimeType, ';', true); } @@ -589,11 +586,11 @@ class OC_Helper { return $newpath; } - + /* * checks if $sub is a subdirectory of $parent - * - * @param $sub + * + * @param $sub * @param $parent * @return bool */ @@ -623,4 +620,68 @@ class OC_Helper { exit;*/ return false; } + + /** + * @brief Returns an array with all keys from input lowercased or uppercased. Numbered indices are left as is. + * + * @param $input The array to work on + * @param $case Either MB_CASE_UPPER or MB_CASE_LOWER (default) + * @param $encoding The encoding parameter is the character encoding. Defaults to UTF-8 + * @return array + * + * Returns an array with all keys from input lowercased or uppercased. Numbered indices are left as is. + * based on http://www.php.net/manual/en/function.array-change-key-case.php#107715 + * + */ + public static function mb_array_change_key_case($input, $case = MB_CASE_LOWER, $encoding = 'UTF-8'){ + $case = ($case != MB_CASE_UPPER) ? MB_CASE_LOWER : MB_CASE_UPPER; + $ret = array(); + foreach ($input as $k => $v) { + $ret[mb_convert_case($k, $case, $encoding)] = $v; + } + return $ret; + } + + /** + * @brief replaces a copy of string delimited by the start and (optionally) length parameters with the string given in replacement. + * + * @param $input The input string. .Opposite to the PHP build-in function does not accept an array. + * @param $replacement The replacement string. + * @param $start If start is positive, the replacing will begin at the start'th offset into string. If start is negative, the replacing will begin at the start'th character from the end of string. + * @param $length Length of the part to be replaced + * @param $encoding The encoding parameter is the character encoding. Defaults to UTF-8 + * @return string + * + */ + public static function mb_substr_replace($string, $replacement, $start, $length = null, $encoding = 'UTF-8') { + $start = intval($start); + $length = intval($length); + $string = mb_substr($string, 0, $start, $encoding) . + $replacement . + mb_substr($string, $start+$length, mb_strlen($string, 'UTF-8')-$start, $encoding); + + return $string; + } + + /** + * @brief Replace all occurrences of the search string with the replacement string + * + * @param $search The value being searched for, otherwise known as the needle. String. + * @param $replace The replacement string. + * @param $subject The string or array being searched and replaced on, otherwise known as the haystack. + * @param $encoding The encoding parameter is the character encoding. Defaults to UTF-8 + * @param $count If passed, this will be set to the number of replacements performed. + * @return string + * + */ + public static function mb_str_replace($search, $replace, $subject, $encoding = 'UTF-8', &$count = null) { + $offset = -1; + $length = mb_strlen($search, 'UTF-8'); + while(($i = mb_strrpos($subject, $search, $offset, 'UTF-8'))) { + $subject = OC_Helper::mb_substr_replace($subject, $replace, $i, $length); + $offset = $i - mb_strlen($subject, 'UTF-8') - 1; + $count++; + } + return $subject; + } } diff --git a/lib/json.php b/lib/json.php index 4eab4fce9f6e5700d9c7ba44bc3f11a76d0ca193..c49b831c12bd18fb7af7d5fa040dd26c9c593dd8 100644 --- a/lib/json.php +++ b/lib/json.php @@ -94,12 +94,12 @@ class OC_JSON{ * Encode and print $data in json format */ public static function encodedPrint($data,$setContentType=true){ - if(!isset($_SERVER['PATH_INFO']) || $_SERVER['PATH_INFO'] == '') { + // Disable mimesniffing, don't move this to setContentTypeHeader! + header( 'X-Content-Type-Options: nosniff' ); if($setContentType){ self::setContentTypeHeader(); } array_walk_recursive($data, array('OC_JSON', 'to_string')); echo json_encode($data); - } } } diff --git a/lib/l10n.php b/lib/l10n.php index 4acbc5dcebc2cfa6f654a8cf835aa72d98009df8..de8514573d393a68db014dfdd7a4694f9f4e169c 100644 --- a/lib/l10n.php +++ b/lib/l10n.php @@ -113,13 +113,13 @@ class OC_L10N{ $i18ndir = self::findI18nDir($app); // Localization is in /l10n, Texts are in $i18ndir // (Just no need to define date/time format etc. twice) - if(file_exists($i18ndir.$lang.'.php')){ + if((OC_Helper::issubdirectory($i18ndir.$lang.'.php', OC_App::getAppPath($app).'/l10n/') || OC_Helper::issubdirectory($i18ndir.$lang.'.php', OC::$SERVERROOT.'/core/l10n/') || OC_Helper::issubdirectory($i18ndir.$lang.'.php', OC::$SERVERROOT.'/settings')) && file_exists($i18ndir.$lang.'.php')) { // Include the file, save the data from $CONFIG - include($i18ndir.$lang.'.php'); + include(strip_tags($i18ndir).strip_tags($lang).'.php'); if(isset($TRANSLATIONS) && is_array($TRANSLATIONS)){ $this->translations = $TRANSLATIONS; } - } + } if(file_exists(OC::$SERVERROOT.'/core/l10n/l10n-'.$lang.'.php')){ // Include the file, save the data from $CONFIG diff --git a/lib/migrate.php b/lib/migrate.php index f26b4b256739d02f57cabbfdbdb6cc49e1b604b3..f788a637d3ce1ae4753c62d34425d1b8adc4bca4 100644 --- a/lib/migrate.php +++ b/lib/migrate.php @@ -64,7 +64,7 @@ class OC_Migrate{ $apps = OC_App::getAllApps(); foreach($apps as $app){ - $path = self::getAppPath($app) . '/appinfo/migrate.php'; + $path = OC_App::getAppPath($app) . '/appinfo/migrate.php'; if( file_exists( $path ) ){ include( $path ); } @@ -278,7 +278,7 @@ class OC_Migrate{ return json_encode( array( 'success' => false ) ); } // Done - return json_encode( 'success' => true ); + return json_encode( array( 'success' => true ) ); */ break; } @@ -398,7 +398,7 @@ class OC_Migrate{ if( OC_App::isEnabled( $provider->getID() ) ){ $success = true; // Does this app use the database? - if( file_exists( self::getAppPath($provider->getID()).'/appinfo/database.xml' ) ){ + if( file_exists( OC_App::getAppPath($provider->getID()).'/appinfo/database.xml' ) ){ // Create some app tables $tables = self::createAppTables( $provider->getID() ); if( is_array( $tables ) ){ @@ -443,21 +443,10 @@ class OC_Migrate{ 'ocversion' => OC_Util::getVersion(), 'exporttime' => time(), 'exportedby' => OC_User::getUser(), - 'exporttype' => self::$exporttype + 'exporttype' => self::$exporttype, + 'exporteduser' => self::$uid ); - // Add hash if user export - if( self::$exporttype == 'user' ){ - $query = OC_DB::prepare( "SELECT password FROM *PREFIX*users WHERE uid = ?" ); - $result = $query->execute( array( self::$uid ) ); - $row = $result->fetchRow(); - $hash = $row ? $row['password'] : false; - if( !$hash ){ - OC_Log::write( 'migration', 'Failed to get the users password hash', OC_log::ERROR); - return false; - } - $info['hash'] = $hash; - $info['exporteduser'] = self::$uid; - } + if( !is_array( $array ) ){ OC_Log::write( 'migration', 'Supplied $array was not an array in getExportInfo()', OC_Log::ERROR ); } @@ -539,7 +528,7 @@ class OC_Migrate{ } // There is a database.xml file - $content = file_get_contents(self::getAppPath($appid) . '/appinfo/database.xml' ); + $content = file_get_contents(OC_App::getAppPath($appid) . '/appinfo/database.xml' ); $file2 = 'static://db_scheme'; // TODO get the relative path to migration.db from the data dir diff --git a/lib/public/util.php b/lib/public/util.php index c611d59a533e4f9a3e12e245a2748b6369c05c7d..41121091544abafecacbedfd9b058de98e00e7db 100644 --- a/lib/public/util.php +++ b/lib/public/util.php @@ -26,7 +26,7 @@ * */ -// use OCP namespace for all classes that are considered public. +// use OCP namespace for all classes that are considered public. // This means that they should be used by apps instead of the internal ownCloud classes namespace OCP; @@ -54,7 +54,7 @@ class Util { /** - * @brief send an email + * @brief send an email * @param string $toaddress * @param string $toname * @param string $subject @@ -264,17 +264,61 @@ class Util { public static function callCheck(){ return(\OC_Util::callCheck()); } - - /** - * @brief Used to sanitize HTML - * - * This function is used to sanitize HTML and should be applied on any string or array of strings before displaying it on a web page. - * - * @param string or array of strings - * @return array with sanitized strings or a single sinitized string, depends on the input parameter. - */ - public static function sanitizeHTML( $value ){ - return(\OC_Util::sanitizeHTML($value)); + + /** + * @brief Used to sanitize HTML + * + * This function is used to sanitize HTML and should be applied on any string or array of strings before displaying it on a web page. + * + * @param string or array of strings + * @return array with sanitized strings or a single sinitized string, depends on the input parameter. + */ + public static function sanitizeHTML( $value ){ + return(\OC_Util::sanitizeHTML($value)); + } + + /** + * @brief Returns an array with all keys from input lowercased or uppercased. Numbered indices are left as is. + * + * @param $input The array to work on + * @param $case Either MB_CASE_UPPER or MB_CASE_LOWER (default) + * @param $encoding The encoding parameter is the character encoding. Defaults to UTF-8 + * @return array + * + * + */ + public static function mb_array_change_key_case($input, $case = MB_CASE_LOWER, $encoding = 'UTF-8'){ + return(\OC_Helper::mb_array_change_key_case($input, $case, $encoding)); + } + + /** + * @brief replaces a copy of string delimited by the start and (optionally) length parameters with the string given in replacement. + * + * @param $input The input string. .Opposite to the PHP build-in function does not accept an array. + * @param $replacement The replacement string. + * @param $start If start is positive, the replacing will begin at the start'th offset into string. If start is negative, the replacing will begin at the start'th character from the end of string. + * @param $length Length of the part to be replaced + * @param $encoding The encoding parameter is the character encoding. Defaults to UTF-8 + * @return string + * + */ + public static function mb_substr_replace($string, $replacement, $start, $length = null, $encoding = 'UTF-8') { + return(\OC_Helper::mb_substr_replace($string, $replacement, $start, $length, $encoding)); + } + + /** + * @brief Replace all occurrences of the search string with the replacement string + * + * @param $search The value being searched for, otherwise known as the needle. String. + * @param $replace The replacement string. + * @param $subject The string or array being searched and replaced on, otherwise known as the haystack. + * @param $encoding The encoding parameter is the character encoding. Defaults to UTF-8 + * @param $count If passed, this will be set to the number of replacements performed. + * @return string + * + */ + public static function mb_str_replace($search, $replace, $subject, $encoding = 'UTF-8', &$count = null) { + return(\OC_Helper::mb_str_replace($search, $replace, $subject, $encoding, $count)); } } diff --git a/lib/setup.php b/lib/setup.php index 5f1fb1525ec8073202ad435f0830ce6132ee353e..bad0f5301c79dad11e7ddcf71ff0eb4a8fc344e1 100644 --- a/lib/setup.php +++ b/lib/setup.php @@ -150,23 +150,28 @@ class OC_Setup { $dbpass = $options['dbpass']; $dbname = $options['dbname']; $dbhost = $options['dbhost']; - $dbtableprefix = $options['dbtableprefix']; + $dbtableprefix = isset($options['dbtableprefix']) ? $options['dbtableprefix'] : 'oc_'; OC_CONFIG::setValue('dbname', $dbname); OC_CONFIG::setValue('dbhost', $dbhost); OC_CONFIG::setValue('dbtableprefix', $dbtableprefix); + $e_host = addslashes($dbhost); + $e_user = addslashes($dbuser); + $e_password = addslashes($dbpass); //check if the database user has admin right - $connection_string = "host=$dbhost dbname=postgres user=$dbuser password=$dbpass"; + $connection_string = "host='$e_host' dbname=postgres user='$e_user' password='$e_password'"; $connection = @pg_connect($connection_string); if(!$connection) { $error[] = array( 'error' => 'PostgreSQL username and/or password not valid', 'hint' => 'You need to enter either an existing account or the administrator.' ); + return $error; } else { + $e_user = pg_escape_string($dbuser); //check for roles creation rights in postgresql - $query="SELECT 1 FROM pg_roles WHERE rolcreaterole=TRUE AND rolname='$dbuser'"; + $query="SELECT 1 FROM pg_roles WHERE rolcreaterole=TRUE AND rolname='$e_user'"; $result = pg_query($connection, $query); if($result and pg_num_rows($result) > 0) { //use the admin login data for the new database user @@ -198,7 +203,13 @@ class OC_Setup { // connect to the ownCloud database (dbname=$dbname) an check if it needs to be filled $dbuser = OC_CONFIG::getValue('dbuser'); $dbpass = OC_CONFIG::getValue('dbpassword'); - $connection_string = "host=$dbhost dbname=$dbname user=$dbuser password=$dbpass"; + + $e_host = addslashes($dbhost); + $e_dbname = addslashes($dbname); + $e_user = addslashes($dbuser); + $e_password = addslashes($dbpass); + + $connection_string = "host='$e_host' dbname='$e_dbname' user='$e_user' password='$e_password'"; $connection = @pg_connect($connection_string); if(!$connection) { $error[] = array( @@ -284,13 +295,23 @@ class OC_Setup { //we cant use OC_BD functions here because we need to connect as the administrative user. $e_name = pg_escape_string($name); $e_user = pg_escape_string($user); - $query = "CREATE DATABASE \"$e_name\" OWNER \"$e_user\""; + $query = "select datname from pg_database where datname = '$e_name'"; $result = pg_query($connection, $query); if(!$result) { $entry='DB Error: "'.pg_last_error($connection).'"<br />'; $entry.='Offending command was: '.$query.'<br />'; echo($entry); } + if(! pg_fetch_row($result)) { + //The database does not exists... let's create it + $query = "CREATE DATABASE \"$e_name\" OWNER \"$e_user\""; + $result = pg_query($connection, $query); + if(!$result) { + $entry='DB Error: "'.pg_last_error($connection).'"<br />'; + $entry.='Offending command was: '.$query.'<br />'; + echo($entry); + } + } $query = "REVOKE ALL PRIVILEGES ON DATABASE \"$e_name\" FROM PUBLIC"; $result = pg_query($connection, $query); } @@ -298,13 +319,33 @@ class OC_Setup { private static function pg_createDBUser($name,$password,$connection) { $e_name = pg_escape_string($name); $e_password = pg_escape_string($password); - $query = "CREATE USER \"$e_name\" CREATEDB PASSWORD '$e_password';"; + $query = "select * from pg_roles where rolname='$e_name';"; $result = pg_query($connection, $query); if(!$result) { $entry='DB Error: "'.pg_last_error($connection).'"<br />'; $entry.='Offending command was: '.$query.'<br />'; echo($entry); } + + if(! pg_fetch_row($result)) { + //user does not exists let's create it :) + $query = "CREATE USER \"$e_name\" CREATEDB PASSWORD '$e_password';"; + $result = pg_query($connection, $query); + if(!$result) { + $entry='DB Error: "'.pg_last_error($connection).'"<br />'; + $entry.='Offending command was: '.$query.'<br />'; + echo($entry); + } + } + else { // change password of the existing role + $query = "ALTER ROLE \"$e_name\" WITH PASSWORD '$e_password';"; + $result = pg_query($connection, $query); + if(!$result) { + $entry='DB Error: "'.pg_last_error($connection).'"<br />'; + $entry.='Offending command was: '.$query.'<br />'; + echo($entry); + } + } } /** diff --git a/lib/util.php b/lib/util.php index 0d9f4129442f445236eb79dba1f8209d826a8aa4..2a7b8a922f9dad7a23ade46c4e2e97b4bcd6fdd8 100755 --- a/lib/util.php +++ b/lib/util.php @@ -324,16 +324,17 @@ class OC_Util { * Redirect to the user default page */ public static function redirectToDefaultPage(){ - OC_Log::write('core','redirectToDefaultPage',OC_Log::DEBUG); if(isset($_REQUEST['redirect_url']) && (substr($_REQUEST['redirect_url'], 0, strlen(OC::$WEBROOT)) == OC::$WEBROOT || $_REQUEST['redirect_url'][0] == '/')) { - header( 'Location: '.$_REQUEST['redirect_url']); + $location = $_REQUEST['redirect_url']; } else if (isset(OC::$REQUESTEDAPP) && !empty(OC::$REQUESTEDAPP)) { - header( 'Location: '.OC::$WEBROOT.'/?app='.OC::$REQUESTEDAPP ); + $location = OC::$WEBROOT.'/?app='.OC::$REQUESTEDAPP; } else { - header( 'Location: '.OC::$WEBROOT.'/'.OC_Appconfig::getValue('core', 'defaultpage', '?app=files')); + $location = OC::$WEBROOT.'/'.OC_Appconfig::getValue('core', 'defaultpage', '?app=files'); } + OC_Log::write('core', 'redirectToDefaultPage: '.$location, OC_Log::DEBUG); + header( 'Location: '.$location ); exit(); } diff --git a/remote.php b/remote.php index af48cd922c898c39570edac446b91818963305ea..bdce867aabaf0755396302c8d5ad345e75b30cbe 100644 --- a/remote.php +++ b/remote.php @@ -25,27 +25,17 @@ if(is_null($file)){ $file = ltrim ($file, '/'); -if(count(explode('/',$file)) == 2) { - $parts=explode('/',$file); - $app=$parts[0]; - switch ($app) { - case 'files': - OC_Util::checkAppEnabled($app); - OC_App::loadApp($app); - break; - case 'core': - break; - default: - OC_Response::setStatus(OC_Response::STATUS_NOT_FOUND); - exit; - } - $baseuri = OC::$WEBROOT . '/remote.php/'.$service.'/'; - require_once( OC::$SERVERROOT.'/'.$file); -} else { - $parts=explode('/', $file, 2); - $app=$parts[0]; - OC_Util::checkAppEnabled($app); - OC_App::loadApp($app); - $baseuri = OC::$WEBROOT . '/remote.php/'.$service.'/'; - require_once(OC_App::getAppPath($app) .'/'. $parts[1]); +$parts=explode('/', $file, 2); +$app=$parts[0]; +switch ($app) { + default: + OC_Util::checkAppEnabled($app); + OC_App::loadApp($app); + $file = OC_App::getAppPath($app) .'/'. $parts[1]; + break; + case 'core': + $file = OC::$SERVERROOT .'/'. $file; + break; } +$baseuri = OC::$WEBROOT . '/remote.php/'.$service.'/'; +require_once($file); diff --git a/settings/js/users.js b/settings/js/users.js index 0de0d1df3bc9ae543326d48f18a406a96ee07483..dfa28e4c4cb39a9f40c2c4e002471f0ea5f1978c 100644 --- a/settings/js/users.js +++ b/settings/js/users.js @@ -4,6 +4,72 @@ * See the COPYING-README file. */ +UserList={ + useUndo:true, + + /** + * @brief Initiate user deletion process in UI + * @param string uid the user ID to be deleted + * + * Does not actually delete the user; it sets them for + * deletion when the current page is unloaded, at which point + * finishDelete() completes the process. This allows for 'undo'. + */ + do_delete:function( uid ) { + + UserList.deleteUid = uid; + + // Set undo flag + UserList.deleteCanceled = false; + + // Hide user in table to reflect deletion + $(this).parent().parent().hide(); + $('tr').filterAttr( 'data-uid', UserList.deleteUid ).hide(); + + // Provide user with option to undo + $('#notification').text(t('files','undo delete user')); + $('#notification').data('deleteuser',true); + $('#notification').fadeIn(); + + }, + + /** + * @brief Delete a user via ajax + * @param bool ready whether to use ready() upon completion + * + * Executes deletion via ajax of user identified by property deleteUid + * if 'undo' has not been used. Completes the user deletion procedure + * and reflects success in UI. + */ + finishDelete:function( ready ){ + + // Check deletion has not been undone + if( !UserList.deleteCanceled && UserList.deleteUid ){ + + // Delete user via ajax + $.post( + OC.filePath('settings','ajax','removeuser.php'), + {username:UserList.deleteUid}, + function(result){ + + // Remove undo option, & remove user from table + boolOperationFinished( + data, function(){ + $('#notification').fadeOut(); + $('tr').filterAttr( 'data-uid', username ).remove(); + UserList.deleteCanceled=true; + UserList.deleteFiles=null; + if( ready ){ + ready(); + } + } + ); + } + ); + } + } +} + $(document).ready(function(){ function setQuota(uid,quota,ready){ $.post( @@ -40,7 +106,15 @@ $(document).ready(function(){ }else{ checkHandeler=false; } + var addGroup = function(group) { + $('select[multiple]').each(function(index, element) { + if ($(element).find('option[value="'+group +'"]').length == 0) { + $(element).append('<option value="'+group+'">'+group+'</option>'); + } + }) + }; element.multiSelect({ + createCallback:addGroup, createText:'add group', checked:checked, oncheck:checkHandeler, @@ -53,15 +127,12 @@ $(document).ready(function(){ }); $('td.remove>img').live('click',function(event){ - var uid=$(this).parent().parent().data('uid'); - $.post( - OC.filePath('settings','ajax','removeuser.php'), - {username:uid}, - function(result){ - - } - ); - $(this).parent().parent().remove(); + + var uid = $(this).parent().parent().data('uid'); + + // Call function for handling delete/undo + UserList.do_delete( uid ); + }); $('td.password>img').live('click',function(event){ @@ -213,6 +284,20 @@ $(document).ready(function(){ } } ); - location.reload(); + }); + // Handle undo notifications + $('#notification').hide(); + $('#notification').click(function(){ + if($('#notification').data('deleteuser')) + { + $( 'tr' ).filterAttr( 'data-uid', UserList.deleteUid ).show(); + UserList.deleteCanceled=true; + UserList.deleteFiles=null; + } + $('#notification').fadeOut(); + }); + UserList.useUndo=('onbeforeunload' in window) + $(window).bind('beforeunload', function (){ + UserList.finishDelete(null); }); }); diff --git a/settings/templates/admin.php b/settings/templates/admin.php index a9f727d6764b4b8f1aacced60ce6c995d5646bbc..033cd1a1642e146b061eb05f83ee789ae66b524f 100755 --- a/settings/templates/admin.php +++ b/settings/templates/admin.php @@ -54,3 +54,10 @@ if(!$_['htaccessworking']) { </table> <input id='moreLog' type='button' value='<?php echo $l->t('More');?>...'></input> </fieldset> + + +<p class="personalblock"> + <strong>ownCloud</strong> <?php echo(OC_Util::getVersionString()); ?> <?php echo(OC_Util::getEditionString()); ?> (<?php echo(OC_Updater::ShowUpdatingHint()); ?>)<br /> + Developed by the <a href="http://ownCloud.org/contact" target="_blank">ownCloud community</a>, the <a href="http://gitorious.org/owncloud" target="_blank">source code</a> is licensed under the <a href="http://www.gnu.org/licenses/agpl-3.0.html" target="_blank"><abbr title="Affero General Public License">AGPL</abbr></a>. +</p> + diff --git a/settings/templates/personal.php b/settings/templates/personal.php index 014996a5b2071c5fd278fabe64c7c08a90449479..ee40120d724b21a9da8dd31370097040c9917fed 100644 --- a/settings/templates/personal.php +++ b/settings/templates/personal.php @@ -55,10 +55,5 @@ echo $form; };?> -<p class="personalblock"> - <strong>ownCloud</strong> <?php echo(OC_Util::getVersionString()); ?> <?php echo(OC_Util::getEditionString()); ?> (<?php echo(OC_Updater::ShowUpdatingHint()); ?>)<br /> - Developed by the <a href="http://ownCloud.org/contact" target="_blank">ownCloud community</a>, the <a href="http://gitorious.org/owncloud" target="_blank">source code</a> is freely licensed under the <a href="http://www.gnu.org/licenses/agpl-3.0.html" target="_blank"><abbr title="Affero General Public License">AGPL</abbr></a>. -</p> - diff --git a/settings/templates/users.php b/settings/templates/users.php index c042f2664e2955cf26facb546b19b21b071ecbd9..551124245610840f60a4b4a487a4de9e4c39887b 100644 --- a/settings/templates/users.php +++ b/settings/templates/users.php @@ -52,6 +52,8 @@ foreach($_["groups"] as $group) { </div> </div> +<div id='notification'></div> + <table data-groups="<?php echo implode(', ',$allGroups);?>"> <thead> <tr> diff --git a/tests/lib/cache/file.php b/tests/lib/cache/file.php index 226e5068c4148fb91dd708db77fed4dafb4dafa3..54e60e6569ddf623500d748d697bd2d2ac0a3fbe 100644 --- a/tests/lib/cache/file.php +++ b/tests/lib/cache/file.php @@ -21,7 +21,26 @@ */ class Test_Cache_File extends Test_Cache { + function skip() { + $this->skipUnless(OC_User::isLoggedIn()); + } + public function setUp(){ + //clear all proxies and hooks so we can do clean testing + OC_FileProxy::clearProxies(); + OC_Hook::clear('OC_Filesystem'); + + //enable only the encryption hook + OC_FileProxy::register(new OC_FileProxy_Encryption()); + + //set up temporary storage + OC_Filesystem::clearMounts(); + OC_Filesystem::mount('OC_Filestorage_Temporary',array(),'/'); + + //set up the users dir + $rootView=new OC_FilesystemView(''); + $rootView->mkdir('/'.OC_User::getUser()); + $this->instance=new OC_Cache_File(); } } diff --git a/tests/lib/cache/xcache.php b/tests/lib/cache/xcache.php index a5e954f827c278d8e4ea5f4d5314df19401322bc..cc2077076cee446f13a1d6d9879a9ea9e546671a 100644 --- a/tests/lib/cache/xcache.php +++ b/tests/lib/cache/xcache.php @@ -28,4 +28,8 @@ class Test_Cache_XCache extends Test_Cache { public function setUp(){ $this->instance=new OC_Cache_XCache(); } + + function testTTL(){ + // ttl doesn't work correctly in the same request + } }