summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRobin Appelman <icewind@owncloud.com>2012-10-26 22:32:44 +0200
committerRobin Appelman <icewind@owncloud.com>2012-10-26 22:32:44 +0200
commit4b616764e825022e9394a4cb26af2012276285b4 (patch)
treecf43a37a9fb7c3a1b96561f0556a2fbe2f9000ca
parentc22a723785f80671548b89c543e9163c2fff9264 (diff)
parent1313cad1b98949195c6aca83a2006d4cc058fc45 (diff)
downloadnextcloud-server-4b616764e825022e9394a4cb26af2012276285b4.tar.gz
nextcloud-server-4b616764e825022e9394a4cb26af2012276285b4.zip
Merge branch 'master' into filesystem
-rw-r--r--apps/user_ldap/lib/access.php135
-rw-r--r--apps/user_ldap/lib/connection.php7
-rw-r--r--apps/user_ldap/user_ldap.php44
-rw-r--r--core/ajax/navigationdetect.php22
-rw-r--r--core/js/jquery.infieldlabel.js140
-rw-r--r--core/js/jquery.infieldlabel.min.js22
-rw-r--r--lib/helper.php13
-rw-r--r--lib/public/share.php31
-rw-r--r--settings/js/apps.js34
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);
+ }
+ }
+ }
+ });
}
};