3 /* ACL selector json backend */
6 use Friendica\Content\Widget;
7 use Friendica\Core\ACL;
8 use Friendica\Core\Addon;
9 use Friendica\Core\Logger;
10 use Friendica\Core\Protocol;
11 use Friendica\Database\DBA;
12 use Friendica\Model\Contact;
13 use Friendica\Model\Item;
14 use Friendica\Util\Proxy as ProxyUtils;
16 require_once 'include/dba.php';
18 function acl_content(App $a)
24 $start = defaults($_REQUEST, 'start' , 0);
25 $count = defaults($_REQUEST, 'count' , 100);
26 $search = defaults($_REQUEST, 'search' , '');
27 $type = defaults($_REQUEST, 'type' , '');
28 $conv_id = defaults($_REQUEST, 'conversation', null);
30 // For use with jquery.textcomplete for private mail completion
31 if (!empty($_REQUEST['query'])) {
35 $search = $_REQUEST['query'];
38 Logger::log("Searching for ".$search." - type ".$type." conversation ".$conv_id, Logger::DEBUG);
41 $sql_extra = "AND `name` LIKE '%%" . DBA::escape($search) . "%%'";
42 $sql_extra2 = "AND (`attag` LIKE '%%" . DBA::escape($search) . "%%' OR `name` LIKE '%%" . DBA::escape($search) . "%%' OR `nick` LIKE '%%" . DBA::escape($search) . "%%')";
44 /// @TODO Avoid these needless else blocks by putting variable-initialization atop of if()
45 $sql_extra = $sql_extra2 = '';
48 // count groups and contacts
50 if ($type == '' || $type == 'g') {
51 $r = q("SELECT COUNT(*) AS g FROM `group` WHERE `deleted` = 0 AND `uid` = %d $sql_extra",
54 $group_count = (int) $r[0]['g'];
57 $sql_extra2 .= ' ' . Widget::unavailableNetworks();
60 if ($type == '' || $type == 'c') {
61 // autocomplete for editor mentions
62 $r = q("SELECT COUNT(*) AS c FROM `contact`
63 WHERE `uid` = %d AND NOT `self`
64 AND NOT `blocked` AND NOT `pending` AND NOT `archive`
65 AND `success_update` >= `failure_update`
66 AND `notify` != '' $sql_extra2",
69 $contact_count = (int) $r[0]['c'];
70 } elseif ($type == 'f') {
71 // autocomplete for editor mentions of forums
72 $r = q("SELECT COUNT(*) AS c FROM `contact`
73 WHERE `uid` = %d AND NOT `self`
74 AND NOT `blocked` AND NOT `pending` AND NOT `archive`
75 AND (`forum` OR `prv`)
76 AND `success_update` >= `failure_update`
77 AND `notify` != '' $sql_extra2",
80 $contact_count = (int) $r[0]['c'];
81 } elseif ($type == 'm') {
82 // autocomplete for Private Messages
83 $r = q("SELECT COUNT(*) AS c FROM `contact`
84 WHERE `uid` = %d AND NOT `self`
85 AND NOT `blocked` AND NOT `pending` AND NOT `archive`
86 AND `success_update` >= `failure_update`
87 AND `network` IN ('%s', '%s', '%s') $sql_extra2",
89 DBA::escape(Protocol::ACTIVITYPUB),
90 DBA::escape(Protocol::DFRN),
91 DBA::escape(Protocol::DIASPORA)
93 $contact_count = (int) $r[0]['c'];
94 } elseif ($type == 'a') {
95 // autocomplete for Contacts
96 $r = q("SELECT COUNT(*) AS c FROM `contact`
97 WHERE `uid` = %d AND NOT `self`
98 AND NOT `pending` $sql_extra2",
101 $contact_count = (int) $r[0]['c'];
104 $tot = $group_count + $contact_count;
109 if ($type == '' || $type == 'g') {
110 /// @todo We should cache this query.
111 // This can be done when we can delete cache entries via wildcard
112 $r = q("SELECT `group`.`id`, `group`.`name`, GROUP_CONCAT(DISTINCT `group_member`.`contact-id` SEPARATOR ',') AS uids
114 INNER JOIN `group_member` ON `group_member`.`gid`=`group`.`id`
115 WHERE NOT `group`.`deleted` AND `group`.`uid` = %d
117 GROUP BY `group`.`name`, `group`.`id`
118 ORDER BY `group`.`name`
120 intval(local_user()),
128 'photo' => 'images/twopeople.png',
129 'name' => htmlentities($g['name']),
130 'id' => intval($g['id']),
131 'uids' => array_map('intval', explode(',', $g['uids'])),
136 if ((count($groups) > 0) && ($search == '')) {
137 $groups[] = ['separator' => true];
143 $r = q("SELECT `id`, `name`, `nick`, `micro`, `network`, `url`, `attag`, `addr`, `forum`, `prv`, (`prv` OR `forum`) AS `frm` FROM `contact`
144 WHERE `uid` = %d AND NOT `self` AND NOT `blocked` AND NOT `pending` AND NOT `archive` AND `notify` != ''
145 AND `success_update` >= `failure_update` AND NOT (`network` IN ('%s', '%s'))
147 ORDER BY `name` ASC ",
148 intval(local_user()),
149 DBA::escape(Protocol::OSTATUS),
150 DBA::escape(Protocol::STATUSNET)
152 } elseif ($type == 'c') {
153 $r = q("SELECT `id`, `name`, `nick`, `micro`, `network`, `url`, `attag`, `addr`, `forum`, `prv` FROM `contact`
154 WHERE `uid` = %d AND NOT `self` AND NOT `blocked` AND NOT `pending` AND NOT `archive` AND `notify` != ''
155 AND `success_update` >= `failure_update` AND NOT (`network` IN ('%s'))
157 ORDER BY `name` ASC ",
158 intval(local_user()),
159 DBA::escape(Protocol::STATUSNET)
161 } elseif ($type == 'f') {
162 $r = q("SELECT `id`, `name`, `nick`, `micro`, `network`, `url`, `attag`, `addr`, `forum`, `prv` FROM `contact`
163 WHERE `uid` = %d AND NOT `self` AND NOT `blocked` AND NOT `pending` AND NOT `archive` AND `notify` != ''
164 AND `success_update` >= `failure_update` AND NOT (`network` IN ('%s'))
165 AND (`forum` OR `prv`)
167 ORDER BY `name` ASC ",
168 intval(local_user()),
169 DBA::escape(Protocol::STATUSNET)
171 } elseif ($type == 'm') {
172 $r = q("SELECT `id`, `name`, `nick`, `micro`, `network`, `url`, `attag`, `addr` FROM `contact`
173 WHERE `uid` = %d AND NOT `self` AND NOT `blocked` AND NOT `pending` AND NOT `archive`
174 AND `success_update` >= `failure_update` AND `network` IN ('%s', '%s', '%s')
176 ORDER BY `name` ASC ",
177 intval(local_user()),
178 DBA::escape(Protocol::ACTIVITYPUB),
179 DBA::escape(Protocol::DFRN),
180 DBA::escape(Protocol::DIASPORA)
182 } elseif ($type == 'a') {
183 $r = q("SELECT `id`, `name`, `nick`, `micro`, `network`, `url`, `attag`, `addr`, `forum`, `prv` FROM `contact`
184 WHERE `uid` = %d AND `pending` = 0 AND `success_update` >= `failure_update`
186 ORDER BY `name` ASC ",
189 } elseif ($type == 'x') {
190 // autocomplete for global contact search (e.g. navbar search)
191 $search = notags(trim($_REQUEST['search']));
192 $mode = $_REQUEST['smode'];
194 $r = ACL::contactAutocomplete($search, $mode);
199 'photo' => ProxyUtils::proxifyUrl($g['photo'], false, ProxyUtils::SIZE_MICRO),
200 'name' => $g['name'],
201 'nick' => defaults($g, 'addr', $g['url']),
202 'network' => $g['network'],
204 'forum' => !empty($g['community']) ? 1 : 0,
210 'items' => $contacts,
212 echo json_encode($o);
216 if (DBA::isResult($r)) {
221 'photo' => ProxyUtils::proxifyUrl($g['micro'], false, ProxyUtils::SIZE_MICRO),
222 'name' => htmlentities($g['name']),
223 'id' => intval($g['id']),
224 'network' => $g['network'],
226 'nick' => htmlentities(defaults($g, 'attag', $g['nick'])),
227 'addr' => htmlentities(defaults($g, 'addr', $g['url'])),
228 'forum' => !empty($g['forum']) || !empty($g['prv']) ? 1 : 0,
230 if ($entry['forum']) {
233 $contacts[] = $entry;
236 if (count($forums) > 0) {
238 $forums[] = ['separator' => true];
240 $contacts = array_merge($forums, $contacts);
244 $items = array_merge($groups, $contacts);
247 // In multi threaded posts the conv_id is not the parent of the whole thread
248 $parent_item = Item::selectFirst(['parent'], ['id' => $conv_id]);
249 if (DBA::isResult($parent_item)) {
250 $conv_id = $parent_item['parent'];
254 * if $conv_id is set, get unknown contacts in thread
255 * but first get known contacts url to filter them out
257 $known_contacts = array_map(function ($i) {
261 $unknown_contacts = [];
263 $condition = ["`parent` = ?", $conv_id];
264 $params = ['order' => ['author-name' => true]];
265 $authors = Item::selectForUser(local_user(), ['author-link'], $condition, $params);
267 while ($author = Item::fetch($authors)) {
268 $item_authors[$author['author-link']] = $author['author-link'];
270 DBA::close($authors);
272 foreach ($item_authors as $author) {
273 if (in_array($author, $known_contacts)) {
277 $contact = Contact::getDetailsByURL($author);
279 if (count($contact) > 0) {
280 $unknown_contacts[] = [
282 'photo' => ProxyUtils::proxifyUrl($contact['micro'], false, ProxyUtils::SIZE_MICRO),
283 'name' => htmlentities($contact['name']),
284 'id' => intval($contact['cid']),
285 'network' => $contact['network'],
286 'link' => $contact['url'],
287 'nick' => htmlentities(defaults($contact, 'nick', $contact['addr'])),
288 'addr' => htmlentities(defaults($contact, 'addr', $contact['url'])),
289 'forum' => $contact['forum']
294 $items = array_merge($items, $unknown_contacts);
295 $tot += count($unknown_contacts);
303 'contacts' => $contacts,
309 Addon::callHooks('acl_lookup_end', $results);
312 'tot' => $results['tot'],
313 'start' => $results['start'],
314 'count' => $results['count'],
315 'items' => $results['items'],
318 echo json_encode($o);