aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRedMatrix <info@friendica.com>2015-01-05 07:30:07 +1100
committerRedMatrix <info@friendica.com>2015-01-05 07:30:07 +1100
commitebb1a616849e275111cd24a20d08031aff4c4161 (patch)
tree72a12265027374eef1fb04a12abaa34c284c7337
parentcb181993a8c63cca8f13c7890a6ab1544f44676f (diff)
parentac4c17dd4c4df70b31fd7246108fdbc9d6f2a593 (diff)
downloadvolse-hubzilla-ebb1a616849e275111cd24a20d08031aff4c4161.tar.gz
volse-hubzilla-ebb1a616849e275111cd24a20d08031aff4c4161.tar.bz2
volse-hubzilla-ebb1a616849e275111cd24a20d08031aff4c4161.zip
Merge pull request #816 from pafcu/acl
Autocomplete improvements
-rwxr-xr-xboot.php1
-rw-r--r--mod/acl.php147
-rw-r--r--view/js/autocomplete.js16
-rwxr-xr-xview/tpl/head.tpl2
-rwxr-xr-xview/tpl/jot-header.tpl2
5 files changed, 88 insertions, 80 deletions
diff --git a/boot.php b/boot.php
index ab2d9671c..54e5676e2 100755
--- a/boot.php
+++ b/boot.php
@@ -1024,6 +1024,7 @@ class App {
'$head_js' => head_get_js(),
'$js_strings' => js_strings(),
'$zid' => get_my_address(),
+ '$channel_id' => $this->profile['uid'],
)) . $this->page['htmlhead'];
// always put main.js at the end
diff --git a/mod/acl.php b/mod/acl.php
index 24f2a35e0..8c6eae0b0 100644
--- a/mod/acl.php
+++ b/mod/acl.php
@@ -13,6 +13,9 @@ function acl_init(&$a){
$type = (x($_REQUEST,'type')?$_REQUEST['type']:"");
$noforums = (x($_REQUEST,'n') ? $_REQUEST['n'] : false);
+ // List of channels whose connections to also suggest, e.g. currently viewed channel or channels mentioned in a post
+ $extra_channels = (x($_REQUEST,'extra_channels') ? $_REQUEST['extra_channels'] : array());
+
// For use with jquery.autocomplete for private mail completion
if(x($_REQUEST,'query') && strlen($_REQUEST['query'])) {
@@ -21,9 +24,8 @@ function acl_init(&$a){
$search = $_REQUEST['query'];
}
-
if(!(local_user()))
- if($type != 'x')
+ if(!($type == 'x' || $type == 'c'))
killme();
if ($search != "") {
@@ -40,72 +42,6 @@ function acl_init(&$a){
$sql_extra = $sql_extra2 = $sql_extra3 = "";
}
- // count groups and contacts
- if ($type=='' || $type=='g'){
- $r = q("SELECT COUNT(`id`) AS g FROM `groups` WHERE `deleted` = 0 AND `uid` = %d $sql_extra",
- intval(local_user())
- );
- $group_count = (int)$r[0]['g'];
- } else {
- $group_count = 0;
- }
-
- if ($type=='' || $type=='c'){
- $r = q("SELECT COUNT(abook_id) AS c FROM abook left join xchan on abook_xchan = xchan_hash
- WHERE abook_channel = %d AND not ( abook_flags & %d )>0 and not (xchan_flags & %d )>0 $sql_extra2" ,
- intval(local_user()),
- intval(ABOOK_FLAG_BLOCKED|ABOOK_FLAG_PENDING|ABOOK_FLAG_ARCHIVED),
- intval(XCHAN_FLAGS_DELETED)
- );
- $contact_count = (int)$r[0]['c'];
-
- if(intval(get_config('system','taganyone')) || intval(get_pconfig(local_user(),'system','taganyone'))) {
- if(((! $r) || (! $r[0]['total'])) && $type == 'c') {
- $r = q("SELECT COUNT(xchan_hash) AS c FROM xchan
- WHERE not (xchan_flags & %d )>0 $sql_extra2" ,
- intval(XCHAN_FLAGS_DELETED)
- );
- $contact_count = (int)$r[0]['c'];
- }
- }
-
- }
-
- elseif ($type == 'm') {
-
- // autocomplete for Private Messages
-
-
- $r = q("SELECT count(xchan_hash) as c
- FROM abook left join xchan on abook_xchan = xchan_hash
- WHERE abook_channel = %d and ( (abook_their_perms = null) or (abook_their_perms & %d )>0)
- and not ( xchan_flags & %d )>0
- $sql_extra2 ",
- intval(local_user()),
- intval(PERMS_W_MAIL),
- intval(XCHAN_FLAGS_DELETED)
- );
-
- if($r)
- $contact_count = (int)$r[0]['c'];
-
- }
- elseif (($type == 'a')||($type == 'p')) {
-
- // autocomplete for Contacts
-
- $r = q("SELECT COUNT(abook_id) AS c FROM abook left join xchan on abook_xchan = xchan_hash
- WHERE abook_channel = %d and not ( xchan_flags & %d )>0 $sql_extra2" ,
- intval(local_user()),
- intval(XCHAN_FLAGS_DELETED)
- );
- $contact_count = (int)$r[0]['c'];
-
- } else {
- $contact_count = 0;
- }
-
- $tot = $group_count+$contact_count;
$groups = array();
$contacts = array();
@@ -142,13 +78,75 @@ function acl_init(&$a){
}
if ($type=='' || $type=='c') {
- $r = q("SELECT abook_id as id, xchan_hash as hash, xchan_name as name, xchan_photo_s as micro, xchan_url as url, xchan_addr as nick, abook_their_perms, abook_flags
+ $extra_channels_sql = '';
+ // Only include channels who allow the observer to view their permissions
+ foreach($extra_channels as $channel) {
+ if(perm_is_allowed(intval($channel), get_observer_hash(),'view_contacts'))
+ $extra_channels_sql .= "," . intval($channel);
+ }
+
+ $extra_channels_sql = substr($extra_channels_sql,1); // Remove initial comma
+
+ // Getting info from the abook is better for local users because it contains info about permissions
+ if(local_user()) {
+ if($extra_channels_sql != '')
+ $extra_channels_sql = " OR (abook_channel IN ($extra_channels_sql)) and not (abook_flags & ". intval(ABOOK_FLAG_HIDDEN) . ') > 0';
+
+ $r = q("SELECT abook_id as id, xchan_hash as hash, xchan_name as name, xchan_photo_s as micro, xchan_url as url, xchan_addr as nick, abook_their_perms, abook_flags
FROM abook left join xchan on abook_xchan = xchan_hash
- WHERE abook_channel = %d AND not ( abook_flags & %d )>0 and not (xchan_flags & %d )>0 $sql_extra2 order by $order_extra2 xchan_name asc" ,
- intval(local_user()),
- intval(ABOOK_FLAG_BLOCKED|ABOOK_FLAG_PENDING|ABOOK_FLAG_ARCHIVED),
- intval(XCHAN_FLAGS_DELETED)
- );
+ WHERE (abook_channel = %d $extra_channels_sql) AND not ( abook_flags & %d )>0 and not (xchan_flags & %d )>0 $sql_extra2 order by $order_extra2 xchan_name asc" ,
+ intval(local_user()),
+ intval(ABOOK_FLAG_BLOCKED|ABOOK_FLAG_PENDING|ABOOK_FLAG_ARCHIVED),
+ intval(XCHAN_FLAGS_DELETED)
+ );
+ }
+ else { // Visitors
+ $r = q("SELECT xchan_hash as id, xchan_hash as hash, xchan_name as name, xchan_photo_s as micro, xchan_url as url, xchan_addr as nick, 0 as abook_their_perms, 0 as abook_flags
+ FROM xchan left join xlink on xlink_link = xchan_hash
+ WHERE xlink_xchan = '%s' AND NOT (xchan_flags & %d) > 0 $sql_extra2 order by $order_extra2 xchan_name asc" ,
+ dbesc(get_observer_hash()),
+ intval(XCHAN_FLAGS_DELETED));
+
+ // Find contacts of extra channels
+ // This is probably more complicated than it needs to be
+ if($extra_channels_sql) {
+ // Build a list of hashes that we got previously so we don't get them again
+ $known_hashes = array("'".get_observer_hash()."'");
+ if($r)
+ foreach($r as $rr)
+ $known_hashes[] = "'".$rr['hash']."'";
+ $known_hashes_sql = 'AND xchan_hash not in ('.join(',',$known_hashes).')';
+
+ $r2 = q("SELECT abook_id as id, xchan_hash as hash, xchan_name as name, xchan_photo_s as micro, xchan_url as url, xchan_addr as nick, abook_their_perms, abook_flags
+ FROM abook left join xchan on abook_xchan = xchan_hash
+ WHERE abook_channel IN ($extra_channels_sql) $known_hashes_sql AND not ( abook_flags & %d )>0 and not (xchan_flags & %d )>0 $sql_extra2 order by $order_extra2 xchan_name asc" ,
+ intval(ABOOK_FLAG_BLOCKED|ABOOK_FLAG_PENDING|ABOOK_FLAG_ARCHIVED|ABOOK_FLAG_HIDDEN),
+ intval(XCHAN_FLAGS_DELETED)
+ );
+ if($r2)
+ $r = array_merge($r,$r2);
+
+ // Sort accoring to match position, then alphabetically. This could be avoided if the above two SQL queries could be combined into one, and the sorting could be done on the SQl server (like in the case of a local user)
+ $matchpos = function($x) use($search) {
+ $namepos = strpos($x['name'],$search);
+ $nickpos = strpos($x['nick'],$search);
+ // Use a large position if not found
+ return min($namepos === false ? 9999 : $namepos, $nickpos === false ? 9999 : $nickpos);
+ };
+ // This could be made simpler if PHP supported stable sorting
+ usort($r,function($a,$b) use($matchpos) {
+ $pos1 = $matchpos($a);
+ $pos2 = $matchpos($b);
+ if($pos1 == $pos2) { // Order alphabetically if match position is the same
+ if($a['name'] == $b['name'])
+ return 0;
+ else
+ return ($a['name'] < $b['name']) ? -1 : 1;
+ }
+ return ($pos1 < $pos2) ? -1 : 1;
+ });
+ }
+ }
if(intval(get_config('system','taganyone')) || intval(get_pconfig(local_user(),'system','taganyone'))) {
if((! $r) && $type == 'c') {
$r = q("SELECT substr(xchan_hash,1,18) as id, xchan_hash as hash, xchan_name as name, xchan_photo_s as micro, xchan_url as url, xchan_addr as nick, 0 as abook_their_perms, 0 as abook_flags
@@ -266,7 +264,6 @@ function acl_init(&$a){
$items = array_merge($groups, $contacts);
$o = array(
- 'tot' => $tot,
'start' => $start,
'count' => $count,
'items' => $items,
diff --git a/view/js/autocomplete.js b/view/js/autocomplete.js
index 7c3145769..259dca1bc 100644
--- a/view/js/autocomplete.js
+++ b/view/js/autocomplete.js
@@ -3,13 +3,16 @@
*
* require jQuery, jquery.textcomplete
*/
-function mysearch(term, callback, backend_url) {
+function mysearch(term, callback, backend_url, extra_channels) {
var postdata = {
start:0,
count:100,
search:term,
type:'c',
}
+
+ if(extra_channels)
+ postdata['extra_channels[]'] = extra_channels;
$.ajax({
type:'POST',
@@ -28,20 +31,25 @@ function format(item) {
function replace(item) {
// $2 ensures that prefix (@,@!) is preserved
- return '$1$2'+item.nick.replace(' ','') + '+' + item.id;
+ var id = item.id;
+ // 16 chars of hash should be enough. Full hash could be used if it can be done in a visually appealing way.
+ // 16 chars is also the minimum length in the backend (otherwise it's interpreted as a local id).
+ if(id.length > 16)
+ id = item.id.substring(0,16);
+ return '$1$2'+item.nick.replace(' ','') + '+' + id;
}
/**
* jQuery plugin 'contact_autocomplete'
*/
(function( $ ){
- $.fn.contact_autocomplete = function(backend_url) {
+ $.fn.contact_autocomplete = function(backend_url, extra_channels = null) {
// Autocomplete contacts
contacts = {
match: /(^|\s)(@\!*)([^ \n]+)$/,
index: 3,
- search: function(term, callback) { mysearch(term, callback, backend_url); },
+ search: function(term, callback) { mysearch(term, callback, backend_url, extra_channels); },
replace: replace,
template: format,
}
diff --git a/view/tpl/head.tpl b/view/tpl/head.tpl
index 9c9e7b970..8a32bd7f6 100755
--- a/view/tpl/head.tpl
+++ b/view/tpl/head.tpl
@@ -26,6 +26,8 @@
var localUser = {{if $local_user}}{{$local_user}}{{else}}false{{/if}};
var zid = {{if $zid}}'{{$zid}}'{{else}}null{{/if}};
var justifiedGalleryActive = false;
+ {{if $channel_hash}}var channelHash = '{{$channel_hash}}';{{/if}}
+ {{if $channel_id}}var channelId = '{{$channel_id}}';{{/if}}{{* Used in e.g. autocomplete *}}
</script>
diff --git a/view/tpl/jot-header.tpl b/view/tpl/jot-header.tpl
index bdbb7d09c..c23395b03 100755
--- a/view/tpl/jot-header.tpl
+++ b/view/tpl/jot-header.tpl
@@ -10,7 +10,7 @@ function initEditor(cb){
if(plaintext == 'none') {
$("#profile-jot-text-loading").spin(false).hide();
$("#profile-jot-text").css({ 'height': 200, 'color': '#000' });
- $("#profile-jot-text").contact_autocomplete(baseurl+"/acl");
+ $("#profile-jot-text").contact_autocomplete(baseurl+"/acl",[channelId]); // Also gives suggestions from current channel's connections
editor = true;
$("a#jot-perms-icon").colorbox({
'inline' : true,