diff options
author | Robin Appelman <icewind@owncloud.com> | 2012-10-26 22:32:44 +0200 |
---|---|---|
committer | Robin Appelman <icewind@owncloud.com> | 2012-10-26 22:32:44 +0200 |
commit | 4b616764e825022e9394a4cb26af2012276285b4 (patch) | |
tree | cf43a37a9fb7c3a1b96561f0556a2fbe2f9000ca | |
parent | c22a723785f80671548b89c543e9163c2fff9264 (diff) | |
parent | 1313cad1b98949195c6aca83a2006d4cc058fc45 (diff) | |
download | nextcloud-server-4b616764e825022e9394a4cb26af2012276285b4.tar.gz nextcloud-server-4b616764e825022e9394a4cb26af2012276285b4.zip |
Merge branch 'master' into filesystem
-rw-r--r-- | apps/user_ldap/lib/access.php | 135 | ||||
-rw-r--r-- | apps/user_ldap/lib/connection.php | 7 | ||||
-rw-r--r-- | apps/user_ldap/user_ldap.php | 44 | ||||
-rw-r--r-- | core/ajax/navigationdetect.php | 22 | ||||
-rw-r--r-- | core/js/jquery.infieldlabel.js | 140 | ||||
-rw-r--r-- | core/js/jquery.infieldlabel.min.js | 22 | ||||
-rw-r--r-- | lib/helper.php | 13 | ||||
-rw-r--r-- | lib/public/share.php | 31 | ||||
-rw-r--r-- | settings/js/apps.js | 34 |
9 files changed, 251 insertions, 197 deletions
diff --git a/apps/user_ldap/lib/access.php b/apps/user_ldap/lib/access.php index 6f2f61dc8a3..aa108f9840e 100644 --- a/apps/user_ldap/lib/access.php +++ b/apps/user_ldap/lib/access.php @@ -26,6 +26,9 @@ namespace OCA\user_ldap\lib; abstract class Access { protected $connection; + //never ever check this var directly, always use getPagedSearchResultState + protected $pagedSearchedSuccessful; + public function setConnector(Connection &$connection) { $this->connection = $connection; } @@ -441,12 +444,12 @@ abstract class Access { return true; } - public function fetchListOfUsers($filter, $attr) { - return $this->fetchList($this->searchUsers($filter, $attr), (count($attr) > 1)); + public function fetchListOfUsers($filter, $attr, $limit = null, $offset = null) { + return $this->fetchList($this->searchUsers($filter, $attr, $limit, $offset), (count($attr) > 1)); } - public function fetchListOfGroups($filter, $attr) { - return $this->fetchList($this->searchGroups($filter, $attr), (count($attr) > 1)); + public function fetchListOfGroups($filter, $attr, $limit = null, $offset = null) { + return $this->fetchList($this->searchGroups($filter, $attr, $limit, $offset), (count($attr) > 1)); } private function fetchList($list, $manyAttributes) { @@ -470,8 +473,8 @@ abstract class Access { * * Executes an LDAP search */ - public function searchUsers($filter, $attr = null) { - return $this->search($filter, $this->connection->ldapBaseUsers, $attr); + public function searchUsers($filter, $attr = null, $limit = null, $offset = null) { + return $this->search($filter, $this->connection->ldapBaseUsers, $attr, $limit, $offset); } /** @@ -482,8 +485,8 @@ abstract class Access { * * Executes an LDAP search */ - public function searchGroups($filter, $attr = null) { - return $this->search($filter, $this->connection->ldapBaseGroups, $attr); + public function searchGroups($filter, $attr = null, $limit = null, $offset = null) { + return $this->search($filter, $this->connection->ldapBaseGroups, $attr, $limit, $offset); } /** @@ -495,29 +498,73 @@ abstract class Access { * * Executes an LDAP search */ - private function search($filter, $base, $attr = null) { + private function search($filter, $base, $attr = null, $limit = null, $offset = null, $skipHandling = false) { if(!is_null($attr) && !is_array($attr)) { $attr = array(mb_strtolower($attr, 'UTF-8')); } - // See if we have a resource + // See if we have a resource, in case not cancel with message $link_resource = $this->connection->getConnectionResource(); - 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 { + if(!is_resource($link_resource)) { // Seems like we didn't find any resource. // Return an empty array just like before. \OCP\Util::writeLog('user_ldap', 'Could not search, because resource is missing.', \OCP\Util::DEBUG); return array(); } + //TODO: lines 516:540 into a function of its own. $pagedSearchOK as return + //check wether paged query should be attempted + $pagedSearchOK = false; + if($this->connection->hasPagedResultSupport && !is_null($limit)) { + $offset = intval($offset); //can be null + //get the cookie from the search for the previous search, required by LDAP + $cookie = $this->getPagedResultCookie($filter, $limit, $offset); + if(empty($cookie) && ($offset > 0)) { + //no cookie known, although the offset is not 0. Maybe cache run out. We need to start all over *sigh* (btw, Dear Reader, did you need LDAP paged searching was designed by MSFT?) + $reOffset = ($offset - $limit) < 0 ? 0 : $offset - $limit; + //a bit recursive, $offset of 0 is the exit + $this->search($filter, $base, $attr, $limit, $reOffset, true); + $cookie = $this->getPagedResultCookie($filter, $limit, $offset); + //still no cookie? obviously, the server does not like us. Let's skip paging efforts. + //TODO: remember this, probably does not change in the next request... + if(empty($cookie)) { + $cookie = null; + } + } + if(!is_null($cookie)) { + $pagedSearchOK = ldap_control_paged_result($link_resource, $limit, false, $cookie); + \OCP\Util::writeLog('user_ldap', 'Ready for a paged search', \OCP\Util::DEBUG); + } else { + \OCP\Util::writeLog('user_ldap', 'No paged search for us, Cpt., Limit '.$limit.' Offset '.$offset, \OCP\Util::DEBUG); + } + } + + $sr = ldap_search($link_resource, $base, $filter, $attr); + $findings = ldap_get_entries($link_resource, $sr ); + if($pagedSearchOK) { + \OCP\Util::writeLog('user_ldap', 'Paged search successful', \OCP\Util::INFO); + ldap_control_paged_result_response($link_resource, $sr, $cookie); + \OCP\Util::writeLog('user_ldap', 'Set paged search cookie '.$cookie, \OCP\Util::INFO); + $this->setPagedResultCookie($filter, $limit, $offset, $cookie); + //browsing through prior pages to get the cookie for the new one + if($skipHandling) { + return; + } + //if count is bigger, then the server does not support paged search. Instead, he did a normal search. We set a flag here, so the callee knows how to deal with it. + //TODO: Not used, just make a count on the returned values in the callee + if($findings['count'] <= $limit) { + $this->pagedSearchedSuccessful = true; + } + } else { + \OCP\Util::writeLog('user_ldap', 'Paged search failed :(', \OCP\Util::INFO); + } + + // 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(); + } + if(!is_null($attr)) { $selection = array(); $multiarray = false; @@ -557,6 +604,7 @@ abstract class Access { } } } +// die(var_dump($selection)); return $selection; } return $findings; @@ -680,4 +728,51 @@ abstract class Access { } return $uuid; } + + /** + * @brief get a cookie for the next LDAP paged search + * @param $filter the search filter to identify the correct search + * @param $limit the limit (or 'pageSize'), to identify the correct search well + * @param $offset the offset for the new search to identify the correct search really good + * @returns string containing the key or empty if none is cached + */ + private function getPagedResultCookie($filter, $limit, $offset) { + if($offset == 0) { + return ''; + } + $offset -= $limit; + //we work with cache here + $cachekey = 'lc' . dechex(crc32($filter)) . '-' . $limit . '-' . $offset; + $cookie = $this->connection->getFromCache($cachekey); + if(is_null($cookie)) { + $cookie = ''; + } + return $cookie; + } + + /** + * @brief set a cookie for LDAP paged search run + * @param $filter the search filter to identify the correct search + * @param $limit the limit (or 'pageSize'), to identify the correct search well + * @param $offset the offset for the run search to identify the correct search really good + * @param $cookie string containing the cookie returned by ldap_control_paged_result_response + * @return void + */ + private function setPagedResultCookie($filter, $limit, $offset) { + if(!empty($cookie)) { + $cachekey = 'lc' . dechex(crc32($filter)) . '-' . $limit . '-' . $offset; + $cookie = $this->connection->writeToCache($cachekey, $cookie); + } + } + + /** + * @brief check wether the most recent paged search was successful. It flushed the state var. Use it always after a possible paged search. + * @return true on success, null or false otherwise + */ + public function getPagedSearchResultState() { + $result = $this->pagedSearchedSuccessful; + $this->pagedSearchedSuccessful = null; + return $result; + } + }
\ No newline at end of file diff --git a/apps/user_ldap/lib/connection.php b/apps/user_ldap/lib/connection.php index bf65d9ad91c..a570b29b793 100644 --- a/apps/user_ldap/lib/connection.php +++ b/apps/user_ldap/lib/connection.php @@ -56,15 +56,20 @@ class Connection { 'ldapUuidAttribute' => null, 'ldapOverrideUuidAttribute' => null, 'homeFolderNamingRule' => null, + 'hasPagedResultSupport' => false, ); public function __construct($configID = 'user_ldap') { $this->configID = $configID; $this->cache = \OC_Cache::getGlobalCache(); + $this->config['hasPagedResultSupport'] = (function_exists('ldap_control_paged_result') && function_exists('ldap_control_paged_result_response')); + \OCP\Util::writeLog('user_ldap', 'PHP supports paged results? '.print_r($this->config['hasPagedResultSupport'], true), \OCP\Util::INFO); } public function __destruct() { - @ldap_unbind($this->ldapConnectionRes); + if(is_resource($this->ldapConnectionRes)) { + @ldap_unbind($this->ldapConnectionRes); + }; } public function __get($name) { diff --git a/apps/user_ldap/user_ldap.php b/apps/user_ldap/user_ldap.php index e104c8d1764..e95bd24fbdd 100644 --- a/apps/user_ldap/user_ldap.php +++ b/apps/user_ldap/user_ldap.php @@ -104,24 +104,38 @@ class USER_LDAP extends lib\Access implements \OCP\UserInterface { * Get a list of all users. */ public function getUsers($search = '', $limit = 10, $offset = 0) { - $ldap_users = $this->connection->getFromCache('getUsers'); - if(is_null($ldap_users)) { - $ldap_users = $this->fetchListOfUsers($this->connection->ldapUserFilter, array($this->connection->ldapUserDisplayName, 'dn')); - $ldap_users = $this->ownCloudUserNames($ldap_users); - $this->connection->writeToCache('getUsers', $ldap_users); - } - $this->userSearch = $search; - if(!empty($this->userSearch)) { - $ldap_users = array_filter($ldap_users, array($this, 'userMatchesFilter')); + $cachekey = 'getUsers-'.$search.'-'.$limit.'-'.$offset; + + //check if users are cached, if so return + $ldap_users = $this->connection->getFromCache($cachekey); + if(!is_null($ldap_users)) { + return $ldap_users; } - if($limit == -1) { - $limit = null; + + //prepare search filter + $search = empty($search) ? '*' : '*'.$search.'*'; + $filter = $this->combineFilterWithAnd(array( + $this->connection->ldapUserFilter, + $this->connection->ldapGroupDisplayName.'='.$search + )); + + \OCP\Util::writeLog('user_ldap', 'getUsers: Get users filter '.$filter, \OCP\Util::DEBUG); + //do the search and translate results to owncloud names + $ldap_users = $this->fetchListOfUsers($filter, array($this->connection->ldapUserDisplayName, 'dn'), $limit, $offset); + $ldap_users = $this->ownCloudUserNames($ldap_users); + + if(!$this->getPagedSearchResultState()) { + \OCP\Util::writeLog('user_ldap', 'getUsers: We got old-style results', \OCP\Util::DEBUG); + //if not supported, a 'normal' search has run automatically, we just need to get our slice of the cake. And we cache the general search, too + $this->connection->writeToCache('getUsers-'.$search, $ldap_users); + $ldap_users = array_slice($ldap_users, $offset, $limit); + } else { + //debug message only + \OCP\Util::writeLog('user_ldap', 'getUsers: We got paged results', \OCP\Util::DEBUG); } - return array_slice($ldap_users, $offset, $limit); - } - public function userMatchesFilter($user) { - return (strripos($user, $this->userSearch) !== false); + $this->connection->writeToCache($cachekey, $ldap_users); + return $ldap_users; } /** diff --git a/core/ajax/navigationdetect.php b/core/ajax/navigationdetect.php new file mode 100644 index 00000000000..c7d0bd38dbc --- /dev/null +++ b/core/ajax/navigationdetect.php @@ -0,0 +1,22 @@ +<?php + +$RUNTIME_NOAPPS = true; + +require_once '../../lib/base.php'; + +OC_Util::checkAdminUser(); +OCP\JSON::callCheck(); + +$app = $_GET['app']; + +//load the one app and see what it adds to the navigation +OC_App::loadApp($app); + +$navigation = OC_App::getNavigation(); + +$navIds = array(); +foreach ($navigation as $nav) { + $navIds[] = $nav['id']; +} + +OCP\JSON::success(array('nav_ids' => array_values($navIds), 'nav_entries' => $navigation)); diff --git a/core/js/jquery.infieldlabel.js b/core/js/jquery.infieldlabel.js deleted file mode 100644 index f6a67b66ce1..00000000000 --- a/core/js/jquery.infieldlabel.js +++ /dev/null @@ -1,140 +0,0 @@ -/* - * In-Field Label jQuery Plugin - * http://fuelyourcoding.com/scripts/infield.html - * - * Copyright (c) 2009 Doug Neiner - * Dual licensed under the MIT and GPL licenses. - * Uses the same license as jQuery, see: - * http://docs.jquery.com/License - * - * @version 0.1 - */ -(function($){ - - $.InFieldLabels = function(label,field, options){ - // To avoid scope issues, use 'base' instead of 'this' - // to reference this class from internal events and functions. - var base = this; - - // Access to jQuery and DOM versions of each element - base.$label = $(label); - base.label = label; - - base.$field = $(field); - base.field = field; - - base.$label.data("InFieldLabels", base); - base.showing = true; - - base.init = function(){ - // Merge supplied options with default options - base.options = $.extend({},$.InFieldLabels.defaultOptions, options); - - // Check if the field is already filled in - if(base.$field.val() != ""){ - base.$label.hide(); - base.showing = false; - }; - - base.$field.focus(function(){ - base.fadeOnFocus(); - }).blur(function(){ - base.checkForEmpty(true); - }).bind('keydown.infieldlabel',function(e){ - // Use of a namespace (.infieldlabel) allows us to - // unbind just this method later - base.hideOnChange(e); - }).change(function(e){ - base.checkForEmpty(); - }).bind('onPropertyChange', function(){ - base.checkForEmpty(); - }); - }; - - // If the label is currently showing - // then fade it down to the amount - // specified in the settings - base.fadeOnFocus = function(){ - if(base.showing){ - base.setOpacity(base.options.fadeOpacity); - }; - }; - - base.setOpacity = function(opacity){ - base.$label.stop().animate({ opacity: opacity }, base.options.fadeDuration); - base.showing = (opacity > 0.0); - }; - - // Checks for empty as a fail safe - // set blur to true when passing from - // the blur event - base.checkForEmpty = function(blur){ - if(base.$field.val() == ""){ - base.prepForShow(); - base.setOpacity( blur ? 1.0 : base.options.fadeOpacity ); - } else { - base.setOpacity(0.0); - }; - }; - - base.prepForShow = function(e){ - if(!base.showing) { - // Prepare for a animate in... - base.$label.css({opacity: 0.0}).show(); - - // Reattach the keydown event - base.$field.bind('keydown.infieldlabel',function(e){ - base.hideOnChange(e); - }); - }; - }; - - base.hideOnChange = function(e){ - if( - (e.keyCode == 16) || // Skip Shift - (e.keyCode == 9) // Skip Tab - ) return; - - if(base.showing){ - base.$label.hide(); - base.showing = false; - }; - - // Remove keydown event to save on CPU processing - base.$field.unbind('keydown.infieldlabel'); - }; - - // Run the initialization method - base.init(); - }; - - $.InFieldLabels.defaultOptions = { - fadeOpacity: 0.5, // Once a field has focus, how transparent should the label be - fadeDuration: 300 // How long should it take to animate from 1.0 opacity to the fadeOpacity - }; - - - $.fn.inFieldLabels = function(options){ - return this.each(function(){ - // Find input or textarea based on for= attribute - // The for attribute on the label must contain the ID - // of the input or textarea element - var for_attr = $(this).attr('for'); - if( !for_attr ) return; // Nothing to attach, since the for field wasn't used - - - // Find the referenced input or textarea element - var $field = $( - "input#" + for_attr + "[type='text']," + - "input#" + for_attr + "[type='password']," + - "textarea#" + for_attr - ); - - if( $field.length == 0) return; // Again, nothing to attach - - // Only create object for input[text], input[password], or textarea - (new $.InFieldLabels(this, $field[0], options)); - }); - }; - -})(jQuery);
\ No newline at end of file diff --git a/core/js/jquery.infieldlabel.min.js b/core/js/jquery.infieldlabel.min.js index 8f0ab9f7c5e..36f6b8f1271 100644 --- a/core/js/jquery.infieldlabel.min.js +++ b/core/js/jquery.infieldlabel.min.js @@ -1,12 +1,12 @@ /* - * In-Field Label jQuery Plugin - * http://fuelyourcoding.com/scripts/infield.html - * - * Copyright (c) 2009 Doug Neiner - * Dual licensed under the MIT and GPL licenses. - * Uses the same license as jQuery, see: - * http://docs.jquery.com/License - * - * @version 0.1 - */ -(function($){$.InFieldLabels=function(b,c,d){var f=this;f.$label=$(b);f.label=b;f.$field=$(c);f.field=c;f.$label.data("InFieldLabels",f);f.showing=true;f.init=function(){f.options=$.extend({},$.InFieldLabels.defaultOptions,d);if(f.$field.val()!=""){f.$label.hide();f.showing=false};f.$field.focus(function(){f.fadeOnFocus()}).blur(function(){f.checkForEmpty(true)}).bind('keydown.infieldlabel',function(e){f.hideOnChange(e)}).change(function(e){f.checkForEmpty()}).bind('onPropertyChange',function(){f.checkForEmpty()})};f.fadeOnFocus=function(){if(f.showing){f.setOpacity(f.options.fadeOpacity)}};f.setOpacity=function(a){f.$label.stop().animate({opacity:a},f.options.fadeDuration);f.showing=(a>0.0)};f.checkForEmpty=function(a){if(f.$field.val()==""){f.prepForShow();f.setOpacity(a?1.0:f.options.fadeOpacity)}else{f.setOpacity(0.0)}};f.prepForShow=function(e){if(!f.showing){f.$label.css({opacity:0.0}).show();f.$field.bind('keydown.infieldlabel',function(e){f.hideOnChange(e)})}};f.hideOnChange=function(e){if((e.keyCode==16)||(e.keyCode==9))return;if(f.showing){f.$label.hide();f.showing=false};f.$field.unbind('keydown.infieldlabel')};f.init()};$.InFieldLabels.defaultOptions={fadeOpacity:0.5,fadeDuration:300};$.fn.inFieldLabels=function(c){return this.each(function(){var a=$(this).attr('for');if(!a)return;var b=$("input#"+a+"[type='text'],"+"input#"+a+"[type='password'],"+"textarea#"+a);if(b.length==0)return;(new $.InFieldLabels(this,b[0],c))})}})(jQuery);
\ No newline at end of file + In-Field Label jQuery Plugin + http://fuelyourcoding.com/scripts/infield.html + + Copyright (c) 2009-2010 Doug Neiner + Dual licensed under the MIT and GPL licenses. + Uses the same license as jQuery, see: + http://docs.jquery.com/License + + @version 0.1.5 +*/ +(function($){$.InFieldLabels=function(label,field,options){var base=this;base.$label=$(label);base.label=label;base.$field=$(field);base.field=field;base.$label.data("InFieldLabels",base);base.showing=true;base.init=function(){base.options=$.extend({},$.InFieldLabels.defaultOptions,options);setTimeout(function(){if(base.$field.val()!==""){base.$label.hide();base.showing=false}},200);base.$field.focus(function(){base.fadeOnFocus()}).blur(function(){base.checkForEmpty(true)}).bind('keydown.infieldlabel',function(e){base.hideOnChange(e)}).bind('paste',function(e){base.setOpacity(0.0)}).change(function(e){base.checkForEmpty()}).bind('onPropertyChange',function(){base.checkForEmpty()}).bind('keyup.infieldlabel',function(){base.checkForEmpty()})};base.fadeOnFocus=function(){if(base.showing){base.setOpacity(base.options.fadeOpacity)}};base.setOpacity=function(opacity){base.$label.stop().animate({opacity:opacity},base.options.fadeDuration);base.showing=(opacity>0.0)};base.checkForEmpty=function(blur){if(base.$field.val()===""){base.prepForShow();base.setOpacity(blur?1.0:base.options.fadeOpacity)}else{base.setOpacity(0.0)}};base.prepForShow=function(e){if(!base.showing){base.$label.css({opacity:0.0}).show();base.$field.bind('keydown.infieldlabel',function(e){base.hideOnChange(e)})}};base.hideOnChange=function(e){if((e.keyCode===16)||(e.keyCode===9)){return}if(base.showing){base.$label.hide();base.showing=false}base.$field.unbind('keydown.infieldlabel')};base.init()};$.InFieldLabels.defaultOptions={fadeOpacity:0.5,fadeDuration:300};$.fn.inFieldLabels=function(options){return this.each(function(){var for_attr=$(this).attr('for'),$field;if(!for_attr){return}$field=$("input#"+for_attr+"[type='text'],"+"input#"+for_attr+"[type='search'],"+"input#"+for_attr+"[type='tel'],"+"input#"+for_attr+"[type='url'],"+"input#"+for_attr+"[type='email'],"+"input#"+for_attr+"[type='password'],"+"textarea#"+for_attr);if($field.length===0){return}(new $.InFieldLabels(this,$field[0],options))})}}(jQuery)); diff --git a/lib/helper.php b/lib/helper.php index 00b974543ad..aa453ad7504 100644 --- a/lib/helper.php +++ b/lib/helper.php @@ -373,20 +373,15 @@ class OC_Helper { } if (!$isWrapped and $mimeType=='application/octet-stream' && OC_Helper::canExecute("file")) { // it looks like we have a 'file' command, - // lets see it it does have mime support + // lets see if it does have mime support $path=escapeshellarg($path); $fp = popen("file -i -b $path 2>/dev/null", "r"); $reply = fgets($fp); pclose($fp); - //trim the character set from the end of the response - $mimeType=substr($reply,0, strrpos($reply,' ')); - $mimeType=substr($mimeType,0, strrpos($mimeType,"\n")); - - //trim ; - if (strpos($mimeType, ';') !== false) { - $mimeType = strstr($mimeType, ';', true); - } + // we have smth like 'text/x-c++; charset=us-ascii\n' + // and need to eliminate everything starting with semicolon including trailing LF + $mimeType = preg_replace('/;.*/ms', '', trim($reply)); } return $mimeType; diff --git a/lib/public/share.php b/lib/public/share.php index d27802b52f7..7a9a087d1bd 100644 --- a/lib/public/share.php +++ b/lib/public/share.php @@ -28,6 +28,9 @@ namespace OCP; /** * This class provides the ability for apps to share their content between users. * Apps must create a backend class that implements OCP\Share_Backend and register it with this class. +* +* It provides the following hooks: +* - post_shared */ class Share { @@ -937,7 +940,20 @@ class Share { // Insert an extra row for the group share if the item or file target is unique for this user if ($itemTarget != $groupItemTarget || (isset($fileSource) && $fileTarget != $groupFileTarget)) { $query->execute(array($itemType, $itemSource, $itemTarget, $parent, self::$shareTypeGroupUserUnique, $uid, $uidOwner, $permissions, time(), $fileSource, $fileTarget)); - \OC_DB::insertid('*PREFIX*share'); + $id = \OC_DB::insertid('*PREFIX*share'); + \OC_Hook::emit('OCP\Share', 'post_shared', array( + 'itemType' => $itemType, + 'itemSource' => $itemSource, + 'itemTarget' => $itemTarget, + 'parent' => $parent, + 'shareType' => self::$shareTypeGroupUserUnique, + 'shareWith' => $uid, + 'uidOwner' => $uidOwner, + 'permissions' => $permissions, + 'fileSource' => $fileSource, + 'fileTarget' => $fileTarget, + 'id' => $id + )); } } if ($parentFolder === true) { @@ -963,6 +979,19 @@ class Share { } $query->execute(array($itemType, $itemSource, $itemTarget, $parent, $shareType, $shareWith, $uidOwner, $permissions, time(), $fileSource, $fileTarget)); $id = \OC_DB::insertid('*PREFIX*share'); + \OC_Hook::emit('OCP\Share', 'post_shared', array( + 'itemType' => $itemType, + 'itemSource' => $itemSource, + 'itemTarget' => $itemTarget, + 'parent' => $parent, + 'shareType' => $shareType, + 'shareWith' => $shareWith, + 'uidOwner' => $uidOwner, + 'permissions' => $permissions, + 'fileSource' => $fileSource, + 'fileTarget' => $fileTarget, + 'id' => $id + )); if ($parentFolder === true) { $parentFolders['id'] = $id; // Return parent folder to preserve file target paths for potential children diff --git a/settings/js/apps.js b/settings/js/apps.js index 8de95100c4c..e45abf9b3dd 100644 --- a/settings/js/apps.js +++ b/settings/js/apps.js @@ -51,6 +51,7 @@ OC.Settings.Apps = OC.Settings.Apps || { } else { element.data('active',false); + OC.Settings.Apps.removeNavigation(appid); element.val(t('settings','Enable')); } },'json'); @@ -61,6 +62,7 @@ OC.Settings.Apps = OC.Settings.Apps || { OC.dialogs.alert('Error while enabling app','Error'); } else { + OC.Settings.Apps.addNavigation(appid); element.data('active',true); element.val(t('settings','Disable')); } @@ -87,6 +89,38 @@ OC.Settings.Apps = OC.Settings.Apps || { applist.last().after(app); } return app; + }, + removeNavigation: function(appid){ + $.getJSON(OC.filePath('core','ajax','navigationdetect.php'), {app: appid}).done(function(response){ + if(response.status === 'success'){ + var navIds=response.nav_ids; + for(var i=0; i< navIds.length; i++){ + $('#apps').children('li[data-id="'+navIds[i]+'"]').remove(); + } + } + }); + }, + addNavigation: function(appid){ + $.getJSON(OC.filePath('core','ajax','navigationdetect.php'), {app: appid}).done(function(response){ + if(response.status === 'success'){ + var navEntries=response.nav_entries; + for(var i=0; i< navEntries.length; i++){ + var entry = navEntries[i]; + var container = $('#apps'); + + if(container.children('li[data-id="'+entry.id+'"]').length === 0){ + var li=$('<li></li>'); + li.attr('data-id', entry.id); + var a=$('<a></a>'); + a.attr('style', 'background-image: url('+entry.icon+')'); + a.text(entry.name); + a.attr('href', entry.href); + li.append(a); + container.append(li); + } + } + } + }); } }; |