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;
15 use Friendica\Util\Strings;
17 require_once 'include/dba.php';
19 function acl_content(App $a)
25 $start = defaults($_REQUEST, 'start' , 0);
26 $count = defaults($_REQUEST, 'count' , 100);
27 $search = defaults($_REQUEST, 'search' , '');
28 $type = defaults($_REQUEST, 'type' , '');
29 $conv_id = defaults($_REQUEST, 'conversation', null);
31 // For use with jquery.textcomplete for private mail completion
32 if (!empty($_REQUEST['query'])) {
36 $search = $_REQUEST['query'];
39 Logger::log("Searching for ".$search." - type ".$type." conversation ".$conv_id, Logger::DEBUG);
42 $sql_extra = "AND `name` LIKE '%%" . DBA::escape($search) . "%%'";
43 $sql_extra2 = "AND (`attag` LIKE '%%" . DBA::escape($search) . "%%' OR `name` LIKE '%%" . DBA::escape($search) . "%%' OR `nick` LIKE '%%" . DBA::escape($search) . "%%')";
45 /// @TODO Avoid these needless else blocks by putting variable-initialization atop of if()
46 $sql_extra = $sql_extra2 = '';
49 // count groups and contacts
51 if ($type == '' || $type == 'g') {
52 $r = q("SELECT COUNT(*) AS g FROM `group` WHERE `deleted` = 0 AND `uid` = %d $sql_extra",
55 $group_count = (int) $r[0]['g'];
58 $sql_extra2 .= ' ' . Widget::unavailableNetworks();
61 if ($type == '' || $type == 'c') {
62 // autocomplete for editor mentions
63 $r = q("SELECT COUNT(*) AS c FROM `contact`
64 WHERE `uid` = %d AND NOT `self`
65 AND NOT `blocked` AND NOT `pending` AND NOT `archive`
66 AND `success_update` >= `failure_update`
67 AND `notify` != '' $sql_extra2",
70 $contact_count = (int) $r[0]['c'];
71 } elseif ($type == 'f') {
72 // autocomplete for editor mentions of forums
73 $r = q("SELECT COUNT(*) AS c FROM `contact`
74 WHERE `uid` = %d AND NOT `self`
75 AND NOT `blocked` AND NOT `pending` AND NOT `archive`
76 AND (`forum` OR `prv`)
77 AND `success_update` >= `failure_update`
78 AND `notify` != '' $sql_extra2",
81 $contact_count = (int) $r[0]['c'];
82 } elseif ($type == 'm') {
83 // autocomplete for Private Messages
84 $r = q("SELECT COUNT(*) AS c FROM `contact`
85 WHERE `uid` = %d AND NOT `self`
86 AND NOT `blocked` AND NOT `pending` AND NOT `archive`
87 AND `success_update` >= `failure_update`
88 AND `network` IN ('%s', '%s', '%s') $sql_extra2",
90 DBA::escape(Protocol::ACTIVITYPUB),
91 DBA::escape(Protocol::DFRN),
92 DBA::escape(Protocol::DIASPORA)
94 $contact_count = (int) $r[0]['c'];
95 } elseif ($type == 'a') {
96 // autocomplete for Contacts
97 $r = q("SELECT COUNT(*) AS c FROM `contact`
98 WHERE `uid` = %d AND NOT `self`
99 AND NOT `pending` $sql_extra2",
102 $contact_count = (int) $r[0]['c'];
105 $tot = $group_count + $contact_count;
110 if ($type == '' || $type == 'g') {
111 /// @todo We should cache this query.
112 // This can be done when we can delete cache entries via wildcard
113 $r = q("SELECT `group`.`id`, `group`.`name`, GROUP_CONCAT(DISTINCT `group_member`.`contact-id` SEPARATOR ',') AS uids
115 INNER JOIN `group_member` ON `group_member`.`gid`=`group`.`id`
116 WHERE NOT `group`.`deleted` AND `group`.`uid` = %d
118 GROUP BY `group`.`name`, `group`.`id`
119 ORDER BY `group`.`name`
121 intval(local_user()),
129 'photo' => 'images/twopeople.png',
130 'name' => htmlentities($g['name']),
131 'id' => intval($g['id']),
132 'uids' => array_map('intval', explode(',', $g['uids'])),
137 if ((count($groups) > 0) && ($search == '')) {
138 $groups[] = ['separator' => true];
144 $r = q("SELECT `id`, `name`, `nick`, `micro`, `network`, `url`, `attag`, `addr`, `forum`, `prv`, (`prv` OR `forum`) AS `frm` FROM `contact`
145 WHERE `uid` = %d AND NOT `self` AND NOT `blocked` AND NOT `pending` AND NOT `archive` AND `notify` != ''
146 AND `success_update` >= `failure_update` AND NOT (`network` IN ('%s', '%s'))
148 ORDER BY `name` ASC ",
149 intval(local_user()),
150 DBA::escape(Protocol::OSTATUS),
151 DBA::escape(Protocol::STATUSNET)
153 } elseif ($type == 'c') {
154 $r = q("SELECT `id`, `name`, `nick`, `micro`, `network`, `url`, `attag`, `addr`, `forum`, `prv` FROM `contact`
155 WHERE `uid` = %d AND NOT `self` AND NOT `blocked` AND NOT `pending` AND NOT `archive` AND `notify` != ''
156 AND `success_update` >= `failure_update` AND NOT (`network` IN ('%s'))
158 ORDER BY `name` ASC ",
159 intval(local_user()),
160 DBA::escape(Protocol::STATUSNET)
162 } elseif ($type == 'f') {
163 $r = q("SELECT `id`, `name`, `nick`, `micro`, `network`, `url`, `attag`, `addr`, `forum`, `prv` FROM `contact`
164 WHERE `uid` = %d AND NOT `self` AND NOT `blocked` AND NOT `pending` AND NOT `archive` AND `notify` != ''
165 AND `success_update` >= `failure_update` AND NOT (`network` IN ('%s'))
166 AND (`forum` OR `prv`)
168 ORDER BY `name` ASC ",
169 intval(local_user()),
170 DBA::escape(Protocol::STATUSNET)
172 } elseif ($type == 'm') {
173 $r = q("SELECT `id`, `name`, `nick`, `micro`, `network`, `url`, `attag`, `addr` FROM `contact`
174 WHERE `uid` = %d AND NOT `self` AND NOT `blocked` AND NOT `pending` AND NOT `archive`
175 AND `success_update` >= `failure_update` AND `network` IN ('%s', '%s', '%s')
177 ORDER BY `name` ASC ",
178 intval(local_user()),
179 DBA::escape(Protocol::ACTIVITYPUB),
180 DBA::escape(Protocol::DFRN),
181 DBA::escape(Protocol::DIASPORA)
183 } elseif ($type == 'a') {
184 $r = q("SELECT `id`, `name`, `nick`, `micro`, `network`, `url`, `attag`, `addr`, `forum`, `prv` FROM `contact`
185 WHERE `uid` = %d AND `pending` = 0 AND `success_update` >= `failure_update`
187 ORDER BY `name` ASC ",
190 } elseif ($type == 'x') {
191 // autocomplete for global contact search (e.g. navbar search)
192 $search = Strings::escapeTags(trim($_REQUEST['search']));
193 $mode = $_REQUEST['smode'];
195 $r = ACL::contactAutocomplete($search, $mode);
200 'photo' => ProxyUtils::proxifyUrl($g['photo'], false, ProxyUtils::SIZE_MICRO),
201 'name' => $g['name'],
202 'nick' => defaults($g, 'addr', $g['url']),
203 'network' => $g['network'],
205 'forum' => !empty($g['community']) ? 1 : 0,
211 'items' => $contacts,
213 echo json_encode($o);
217 if (DBA::isResult($r)) {
222 'photo' => ProxyUtils::proxifyUrl($g['micro'], false, ProxyUtils::SIZE_MICRO),
223 'name' => htmlentities($g['name']),
224 'id' => intval($g['id']),
225 'network' => $g['network'],
227 'nick' => htmlentities(defaults($g, 'attag', $g['nick'])),
228 'addr' => htmlentities(defaults($g, 'addr', $g['url'])),
229 'forum' => !empty($g['forum']) || !empty($g['prv']) ? 1 : 0,
231 if ($entry['forum']) {
234 $contacts[] = $entry;
237 if (count($forums) > 0) {
239 $forums[] = ['separator' => true];
241 $contacts = array_merge($forums, $contacts);
245 $items = array_merge($groups, $contacts);
248 // In multi threaded posts the conv_id is not the parent of the whole thread
249 $parent_item = Item::selectFirst(['parent'], ['id' => $conv_id]);
250 if (DBA::isResult($parent_item)) {
251 $conv_id = $parent_item['parent'];
255 * if $conv_id is set, get unknown contacts in thread
256 * but first get known contacts url to filter them out
258 $known_contacts = array_map(function ($i) {
262 $unknown_contacts = [];
264 $condition = ["`parent` = ?", $conv_id];
265 $params = ['order' => ['author-name' => true]];
266 $authors = Item::selectForUser(local_user(), ['author-link'], $condition, $params);
268 while ($author = Item::fetch($authors)) {
269 $item_authors[$author['author-link']] = $author['author-link'];
271 DBA::close($authors);
273 foreach ($item_authors as $author) {
274 if (in_array($author, $known_contacts)) {
278 $contact = Contact::getDetailsByURL($author);
280 if (count($contact) > 0) {
281 $unknown_contacts[] = [
283 'photo' => ProxyUtils::proxifyUrl($contact['micro'], false, ProxyUtils::SIZE_MICRO),
284 'name' => htmlentities($contact['name']),
285 'id' => intval($contact['cid']),
286 'network' => $contact['network'],
287 'link' => $contact['url'],
288 'nick' => htmlentities(defaults($contact, 'nick', $contact['addr'])),
289 'addr' => htmlentities(defaults($contact, 'addr', $contact['url'])),
290 'forum' => $contact['forum']
295 $items = array_merge($items, $unknown_contacts);
296 $tot += count($unknown_contacts);
304 'contacts' => $contacts,
310 Addon::callHooks('acl_lookup_end', $results);
313 'tot' => $results['tot'],
314 'start' => $results['start'],
315 'count' => $results['count'],
316 'items' => $results['items'],
319 echo json_encode($o);