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/acl_selectors.php';
13 require_once 'include/dba.php';
14 require_once 'mod/proxy.php';
16 function acl_content(App $a)
22 $start = defaults($_REQUEST, 'start', 0);
23 $count = defaults($_REQUEST, 'count', 100);
24 $search = defaults($_REQUEST, 'search', '');
25 $type = defaults($_REQUEST, 'type', '');
26 $conv_id = defaults($_REQUEST, 'conversation', null);
28 // For use with jquery.textcomplete for private mail completion
29 if (x($_REQUEST, 'query')) {
33 $search = $_REQUEST['query'];
36 logger('Searching for ' . $search . ' - type ' . $type, LOGGER_DEBUG);
39 $sql_extra = "AND `name` LIKE '%%" . dbesc($search) . "%%'";
40 $sql_extra2 = "AND (`attag` LIKE '%%" . dbesc($search) . "%%' OR `name` LIKE '%%" . dbesc($search) . "%%' OR `nick` LIKE '%%" . dbesc($search) . "%%')";
42 /// @TODO Avoid these needless else blocks by putting variable-initialization atop of if()
43 $sql_extra = $sql_extra2 = '';
46 // 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'];
56 $sql_extra2 .= ' ' . Widget::unavailableNetworks();
58 if ($type == '' || $type == 'c') {
59 // autocomplete for editor mentions
60 $r = q("SELECT COUNT(*) AS c FROM `contact`
61 WHERE `uid` = %d AND NOT `self`
62 AND NOT `blocked` AND NOT `pending` AND NOT `archive`
63 AND `success_update` >= `failure_update`
64 AND `notify` != '' $sql_extra2",
67 $contact_count = (int) $r[0]['c'];
68 } elseif ($type == 'f') {
69 // autocomplete for editor mentions of forums
70 $r = q("SELECT COUNT(*) AS c FROM `contact`
71 WHERE `uid` = %d AND NOT `self`
72 AND NOT `blocked` AND NOT `pending` AND NOT `archive`
73 AND (`forum` OR `prv`)
74 AND `success_update` >= `failure_update`
75 AND `notify` != '' $sql_extra2",
78 $contact_count = (int) $r[0]['c'];
79 } elseif ($type == 'm') {
80 // autocomplete for Private Messages
81 $r = q("SELECT COUNT(*) AS c FROM `contact`
82 WHERE `uid` = %d AND NOT `self`
83 AND NOT `blocked` AND NOT `pending` AND NOT `archive`
84 AND `success_update` >= `failure_update`
85 AND `network` IN ('%s', '%s') $sql_extra2",
88 dbesc(NETWORK_DIASPORA)
90 $contact_count = (int) $r[0]['c'];
91 } elseif ($type == 'a') {
92 // autocomplete for Contacts
93 $r = q("SELECT COUNT(*) AS c FROM `contact`
94 WHERE `uid` = %d AND NOT `self`
95 AND NOT `pending` $sql_extra2",
98 $contact_count = (int) $r[0]['c'];
103 $tot = $group_count + $contact_count;
108 if ($type == '' || $type == 'g') {
109 /// @todo We should cache this query.
110 // This can be done when we can delete cache entries via wildcard
111 $r = q("SELECT `group`.`id`, `group`.`name`, GROUP_CONCAT(DISTINCT `group_member`.`contact-id` SEPARATOR ',') AS uids
113 INNER JOIN `group_member` ON `group_member`.`gid`=`group`.`id`
114 WHERE NOT `group`.`deleted` AND `group`.`uid` = %d
116 GROUP BY `group`.`name`, `group`.`id`
117 ORDER BY `group`.`name`
119 intval(local_user()),
127 'photo' => 'images/twopeople.png',
128 'name' => htmlentities($g['name']),
129 'id' => intval($g['id']),
130 'uids' => array_map('intval', explode(',', $g['uids'])),
135 if ((count($groups) > 0) && ($search == '')) {
136 $groups[] = ['separator' => true];
141 $r = q("SELECT `id`, `name`, `nick`, `micro`, `network`, `url`, `attag`, `addr`, `forum`, `prv`, (`prv` OR `forum`) AS `frm` FROM `contact`
142 WHERE `uid` = %d AND NOT `self` AND NOT `blocked` AND NOT `pending` AND NOT `archive` AND `notify` != ''
143 AND `success_update` >= `failure_update` AND NOT (`network` IN ('%s', '%s'))
145 ORDER BY `name` ASC ",
146 intval(local_user()),
147 dbesc(NETWORK_OSTATUS),
148 dbesc(NETWORK_STATUSNET)
150 } elseif ($type == 'c') {
151 $r = q("SELECT `id`, `name`, `nick`, `micro`, `network`, `url`, `attag`, `addr`, `forum`, `prv` FROM `contact`
152 WHERE `uid` = %d AND NOT `self` AND NOT `blocked` AND NOT `pending` AND NOT `archive` AND `notify` != ''
153 AND `success_update` >= `failure_update` AND NOT (`network` IN ('%s'))
155 ORDER BY `name` ASC ",
156 intval(local_user()),
157 dbesc(NETWORK_STATUSNET)
159 } elseif ($type == 'f') {
160 $r = q("SELECT `id`, `name`, `nick`, `micro`, `network`, `url`, `attag`, `addr`, `forum`, `prv` FROM `contact`
161 WHERE `uid` = %d AND NOT `self` AND NOT `blocked` AND NOT `pending` AND NOT `archive` AND `notify` != ''
162 AND `success_update` >= `failure_update` AND NOT (`network` IN ('%s'))
163 AND (`forum` OR `prv`)
165 ORDER BY `name` ASC ",
166 intval(local_user()),
167 dbesc(NETWORK_STATUSNET)
169 } elseif ($type == 'm') {
170 $r = q("SELECT `id`, `name`, `nick`, `micro`, `network`, `url`, `attag`, `addr` FROM `contact`
171 WHERE `uid` = %d AND NOT `self` AND NOT `blocked` AND NOT `pending` AND NOT `archive`
172 AND `success_update` >= `failure_update` AND `network` IN ('%s', '%s')
174 ORDER BY `name` ASC ",
175 intval(local_user()),
177 dbesc(NETWORK_DIASPORA)
179 } elseif ($type == 'a') {
180 $r = q("SELECT `id`, `name`, `nick`, `micro`, `network`, `url`, `attag`, `addr`, `forum`, `prv` FROM `contact`
181 WHERE `uid` = %d AND `pending` = 0 AND `success_update` >= `failure_update`
183 ORDER BY `name` ASC ",
186 } elseif ($type == 'x') {
187 // autocomplete for global contact search (e.g. navbar search)
188 $search = notags(trim($_REQUEST['search']));
189 $mode = $_REQUEST['smode'];
191 $r = Acl::contactAutocomplete($search, $mode);
196 'photo' => proxy_url($g['photo'], false, PROXY_SIZE_MICRO),
197 'name' => $g['name'],
198 'nick' => (x($g['addr']) ? $g['addr'] : $g['url']),
199 'network' => $g['network'],
201 'forum' => (x($g['community']) ? 1 : 0),
207 'items' => $contacts,
209 echo json_encode($o);
215 if (DBM::is_result($r)) {
220 'photo' => proxy_url($g['micro'], false, PROXY_SIZE_MICRO),
221 'name' => htmlentities($g['name']),
222 'id' => intval($g['id']),
223 'network' => $g['network'],
225 'nick' => htmlentities(($g['attag']) ? $g['attag'] : $g['nick']),
226 'addr' => htmlentities(($g['addr']) ? $g['addr'] : $g['url']),
227 'forum' => ((x($g, 'forum') || x($g, 'prv')) ? 1 : 0),
229 if ($entry['forum']) {
232 $contacts[] = $entry;
235 if (count($forums) > 0) {
237 $forums[] = ['separator' => true];
239 $contacts = array_merge($forums, $contacts);
243 $items = array_merge($groups, $contacts);
247 * if $conv_id is set, get unknown contacts in thread
248 * but first get known contacts url to filter them out
250 $known_contacts = array_map(function ($i) {
251 return dbesc($i['link']);
254 $unknown_contacts = [];
255 $r = q("SELECT `author-link`
256 FROM `item` WHERE `parent` = %d
257 AND (`author-name` LIKE '%%%s%%' OR `author-link` LIKE '%%%s%%')
258 AND `author-link` NOT IN ('%s')
259 GROUP BY `author-link`, `author-avatar`, `author-name`
260 ORDER BY `author-name` ASC
265 implode("', '", $known_contacts)
267 if (DBM::is_result($r)) {
268 foreach ($r as $row) {
269 $contact = Contact::getDetailsByURL($row['author-link']);
271 if (count($contact) > 0) {
272 $unknown_contacts[] = [
274 'photo' => proxy_url($contact['micro'], false, PROXY_SIZE_MICRO),
275 'name' => htmlentities($contact['name']),
276 'id' => intval($contact['cid']),
277 'network' => $contact['network'],
278 'link' => $contact['url'],
279 'nick' => htmlentities($contact['nick'] ?: $contact['addr']),
280 'addr' => htmlentities(($contact['addr']) ? $contact['addr'] : $contact['url']),
281 'forum' => $contact['forum']
287 $items = array_merge($items, $unknown_contacts);
288 $tot += count($unknown_contacts);
296 'contacts' => $contacts,
302 Addon::callHooks('acl_lookup_end', $results);
305 'tot' => $results['tot'],
306 'start' => $results['start'],
307 'count' => $results['count'],
308 'items' => $results['items'],
311 echo json_encode($o);