3 /* ACL selector json backend */
6 use Friendica\Content\Widget;
7 use Friendica\Core\ACL;
8 use Friendica\Core\Addon;
9 use Friendica\Database\DBM;
10 use Friendica\Model\Contact;
12 require_once 'include/dba.php';
13 require_once 'mod/proxy.php';
15 function acl_content(App $a)
21 $start = defaults($_REQUEST, 'start' , 0);
22 $count = defaults($_REQUEST, 'count' , 100);
23 $search = defaults($_REQUEST, 'search' , '');
24 $type = defaults($_REQUEST, 'type' , '');
25 $conv_id = defaults($_REQUEST, 'conversation', null);
27 // For use with jquery.textcomplete for private mail completion
28 if (!empty($_REQUEST['query'])) {
32 $search = $_REQUEST['query'];
35 logger("Searching for ".$search." - type ".$type." conversation ".$conv_id, LOGGER_DEBUG);
38 $sql_extra = "AND `name` LIKE '%%" . dbesc($search) . "%%'";
39 $sql_extra2 = "AND (`attag` LIKE '%%" . dbesc($search) . "%%' OR `name` LIKE '%%" . dbesc($search) . "%%' OR `nick` LIKE '%%" . dbesc($search) . "%%')";
41 /// @TODO Avoid these needless else blocks by putting variable-initialization atop of if()
42 $sql_extra = $sql_extra2 = '';
45 // count groups and contacts
47 if ($type == '' || $type == 'g') {
48 $r = q("SELECT COUNT(*) AS g FROM `group` WHERE `deleted` = 0 AND `uid` = %d $sql_extra",
51 $group_count = (int) $r[0]['g'];
54 $sql_extra2 .= ' ' . Widget::unavailableNetworks();
57 if ($type == '' || $type == 'c') {
58 // autocomplete for editor mentions
59 $r = q("SELECT COUNT(*) AS c FROM `contact`
60 WHERE `uid` = %d AND NOT `self`
61 AND NOT `blocked` AND NOT `pending` AND NOT `archive`
62 AND `success_update` >= `failure_update`
63 AND `notify` != '' $sql_extra2",
66 $contact_count = (int) $r[0]['c'];
67 } elseif ($type == 'f') {
68 // autocomplete for editor mentions of forums
69 $r = q("SELECT COUNT(*) AS c FROM `contact`
70 WHERE `uid` = %d AND NOT `self`
71 AND NOT `blocked` AND NOT `pending` AND NOT `archive`
72 AND (`forum` OR `prv`)
73 AND `success_update` >= `failure_update`
74 AND `notify` != '' $sql_extra2",
77 $contact_count = (int) $r[0]['c'];
78 } elseif ($type == 'm') {
79 // autocomplete for Private Messages
80 $r = q("SELECT COUNT(*) AS c FROM `contact`
81 WHERE `uid` = %d AND NOT `self`
82 AND NOT `blocked` AND NOT `pending` AND NOT `archive`
83 AND `success_update` >= `failure_update`
84 AND `network` IN ('%s', '%s') $sql_extra2",
87 dbesc(NETWORK_DIASPORA)
89 $contact_count = (int) $r[0]['c'];
90 } elseif ($type == 'a') {
91 // autocomplete for Contacts
92 $r = q("SELECT COUNT(*) AS c FROM `contact`
93 WHERE `uid` = %d AND NOT `self`
94 AND NOT `pending` $sql_extra2",
97 $contact_count = (int) $r[0]['c'];
100 $tot = $group_count + $contact_count;
105 if ($type == '' || $type == 'g') {
106 /// @todo We should cache this query.
107 // This can be done when we can delete cache entries via wildcard
108 $r = q("SELECT `group`.`id`, `group`.`name`, GROUP_CONCAT(DISTINCT `group_member`.`contact-id` SEPARATOR ',') AS uids
110 INNER JOIN `group_member` ON `group_member`.`gid`=`group`.`id`
111 WHERE NOT `group`.`deleted` AND `group`.`uid` = %d
113 GROUP BY `group`.`name`, `group`.`id`
114 ORDER BY `group`.`name`
116 intval(local_user()),
124 'photo' => 'images/twopeople.png',
125 'name' => htmlentities($g['name']),
126 'id' => intval($g['id']),
127 'uids' => array_map('intval', explode(',', $g['uids'])),
132 if ((count($groups) > 0) && ($search == '')) {
133 $groups[] = ['separator' => true];
139 $r = q("SELECT `id`, `name`, `nick`, `micro`, `network`, `url`, `attag`, `addr`, `forum`, `prv`, (`prv` OR `forum`) AS `frm` FROM `contact`
140 WHERE `uid` = %d AND NOT `self` AND NOT `blocked` AND NOT `pending` AND NOT `archive` AND `notify` != ''
141 AND `success_update` >= `failure_update` AND NOT (`network` IN ('%s', '%s'))
143 ORDER BY `name` ASC ",
144 intval(local_user()),
145 dbesc(NETWORK_OSTATUS),
146 dbesc(NETWORK_STATUSNET)
148 } elseif ($type == 'c') {
149 $r = q("SELECT `id`, `name`, `nick`, `micro`, `network`, `url`, `attag`, `addr`, `forum`, `prv` FROM `contact`
150 WHERE `uid` = %d AND NOT `self` AND NOT `blocked` AND NOT `pending` AND NOT `archive` AND `notify` != ''
151 AND `success_update` >= `failure_update` AND NOT (`network` IN ('%s'))
153 ORDER BY `name` ASC ",
154 intval(local_user()),
155 dbesc(NETWORK_STATUSNET)
157 } elseif ($type == 'f') {
158 $r = q("SELECT `id`, `name`, `nick`, `micro`, `network`, `url`, `attag`, `addr`, `forum`, `prv` FROM `contact`
159 WHERE `uid` = %d AND NOT `self` AND NOT `blocked` AND NOT `pending` AND NOT `archive` AND `notify` != ''
160 AND `success_update` >= `failure_update` AND NOT (`network` IN ('%s'))
161 AND (`forum` OR `prv`)
163 ORDER BY `name` ASC ",
164 intval(local_user()),
165 dbesc(NETWORK_STATUSNET)
167 } elseif ($type == 'm') {
168 $r = q("SELECT `id`, `name`, `nick`, `micro`, `network`, `url`, `attag`, `addr` FROM `contact`
169 WHERE `uid` = %d AND NOT `self` AND NOT `blocked` AND NOT `pending` AND NOT `archive`
170 AND `success_update` >= `failure_update` AND `network` IN ('%s', '%s')
172 ORDER BY `name` ASC ",
173 intval(local_user()),
175 dbesc(NETWORK_DIASPORA)
177 } elseif ($type == 'a') {
178 $r = q("SELECT `id`, `name`, `nick`, `micro`, `network`, `url`, `attag`, `addr`, `forum`, `prv` FROM `contact`
179 WHERE `uid` = %d AND `pending` = 0 AND `success_update` >= `failure_update`
181 ORDER BY `name` ASC ",
184 } elseif ($type == 'x') {
185 // autocomplete for global contact search (e.g. navbar search)
186 $search = notags(trim($_REQUEST['search']));
187 $mode = $_REQUEST['smode'];
189 $r = ACL::contactAutocomplete($search, $mode);
194 'photo' => proxy_url($g['photo'], false, PROXY_SIZE_MICRO),
195 'name' => $g['name'],
196 'nick' => defaults($g, 'addr', $g['url']),
197 'network' => $g['network'],
199 'forum' => !empty($g['community']) ? 1 : 0,
205 'items' => $contacts,
207 echo json_encode($o);
211 if (DBM::is_result($r)) {
216 'photo' => proxy_url($g['micro'], false, PROXY_SIZE_MICRO),
217 'name' => htmlentities($g['name']),
218 'id' => intval($g['id']),
219 'network' => $g['network'],
221 'nick' => htmlentities(defaults($g, 'attag', $g['nick'])),
222 'addr' => htmlentities(defaults($g, 'addr', $g['url'])),
223 'forum' => !empty($g['forum']) || !empty($g['prv']) ? 1 : 0,
225 if ($entry['forum']) {
228 $contacts[] = $entry;
231 if (count($forums) > 0) {
233 $forums[] = ['separator' => true];
235 $contacts = array_merge($forums, $contacts);
239 $items = array_merge($groups, $contacts);
242 // In multi threaded posts the conv_id is not the parent of the whole thread
243 $parent_item = dba::selectFirst('item', ['parent'], ['id' => $conv_id]);
244 if (DBM::is_result($parent_item)) {
245 $conv_id = $parent_item['parent'];
249 * if $conv_id is set, get unknown contacts in thread
250 * but first get known contacts url to filter them out
252 $known_contacts = array_map(function ($i) {
253 return dbesc($i['link']);
256 $unknown_contacts = [];
257 $r = q("SELECT `author-link`
258 FROM `item` WHERE `parent` = %d
259 AND (`author-name` LIKE '%%%s%%' OR `author-link` LIKE '%%%s%%')
260 AND `author-link` NOT IN ('%s')
261 GROUP BY `author-link`, `author-avatar`, `author-name`
262 ORDER BY `author-name` ASC
267 implode("', '", $known_contacts)
269 if (DBM::is_result($r)) {
270 foreach ($r as $row) {
271 $contact = Contact::getDetailsByURL($row['author-link']);
273 if (count($contact) > 0) {
274 $unknown_contacts[] = [
276 'photo' => proxy_url($contact['micro'], false, PROXY_SIZE_MICRO),
277 'name' => htmlentities($contact['name']),
278 'id' => intval($contact['cid']),
279 'network' => $contact['network'],
280 'link' => $contact['url'],
281 'nick' => htmlentities(defaults($contact, 'nick', $contact['addr'])),
282 'addr' => htmlentities(defaults($contact, 'addr', $contact['url'])),
283 'forum' => $contact['forum']
289 $items = array_merge($items, $unknown_contacts);
290 $tot += count($unknown_contacts);
298 'contacts' => $contacts,
304 Addon::callHooks('acl_lookup_end', $results);
307 'tot' => $results['tot'],
308 'start' => $results['start'],
309 'count' => $results['count'],
310 'items' => $results['items'],
313 echo json_encode($o);