Friendica Communications Platform (please note that this is a clone of the repository at github, issues are handled there) https://friendi.ca
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

320 lines
9.9KB

  1. <?php
  2. /* ACL selector json backend */
  3. use Friendica\App;
  4. use Friendica\Content\Widget;
  5. use Friendica\Core\ACL;
  6. use Friendica\Core\Hook;
  7. use Friendica\Core\Logger;
  8. use Friendica\Core\Protocol;
  9. use Friendica\Database\DBA;
  10. use Friendica\Model\Contact;
  11. use Friendica\Model\Item;
  12. use Friendica\Util\Proxy as ProxyUtils;
  13. use Friendica\Util\Strings;
  14. function acl_content(App $a)
  15. {
  16. if (!local_user()) {
  17. return '';
  18. }
  19. $start = defaults($_REQUEST, 'start' , 0);
  20. $count = defaults($_REQUEST, 'count' , 100);
  21. $search = defaults($_REQUEST, 'search' , '');
  22. $type = defaults($_REQUEST, 'type' , '');
  23. $conv_id = defaults($_REQUEST, 'conversation', null);
  24. // For use with jquery.textcomplete for private mail completion
  25. if (!empty($_REQUEST['query'])) {
  26. if (!$type) {
  27. $type = 'm';
  28. }
  29. $search = $_REQUEST['query'];
  30. }
  31. $a->getLogger()->info("Searching for " . $search . " - type " . $type . " conversation " . $conv_id);
  32. if ($search != '') {
  33. $sql_extra = "AND `name` LIKE '%%" . DBA::escape($search) . "%%'";
  34. $sql_extra2 = "AND (`attag` LIKE '%%" . DBA::escape($search) . "%%' OR `name` LIKE '%%" . DBA::escape($search) . "%%' OR `nick` LIKE '%%" . DBA::escape($search) . "%%')";
  35. } else {
  36. /// @TODO Avoid these needless else blocks by putting variable-initialization atop of if()
  37. $sql_extra = $sql_extra2 = '';
  38. }
  39. // count groups and contacts
  40. $group_count = 0;
  41. if ($type == '' || $type == 'g') {
  42. $r = q("SELECT COUNT(*) AS g FROM `group` WHERE NOT `deleted` AND `uid` = %d $sql_extra",
  43. intval(local_user())
  44. );
  45. $group_count = (int) $r[0]['g'];
  46. }
  47. $sql_extra2 .= ' ' . Widget::unavailableNetworks();
  48. $contact_count = 0;
  49. if ($type == '' || $type == 'c') {
  50. // autocomplete for editor mentions
  51. $r = q("SELECT COUNT(*) AS c FROM `contact`
  52. WHERE `uid` = %d AND NOT `self` AND NOT `deleted`
  53. AND NOT `blocked` AND NOT `pending` AND NOT `archive`
  54. AND `success_update` >= `failure_update`
  55. AND `notify` != '' $sql_extra2",
  56. intval(local_user())
  57. );
  58. $contact_count = (int) $r[0]['c'];
  59. } elseif ($type == 'f') {
  60. // autocomplete for editor mentions of forums
  61. $r = q("SELECT COUNT(*) AS c FROM `contact`
  62. WHERE `uid` = %d AND NOT `self` AND NOT `deleted`
  63. AND NOT `blocked` AND NOT `pending` AND NOT `archive`
  64. AND (`forum` OR `prv`)
  65. AND `success_update` >= `failure_update`
  66. AND `notify` != '' $sql_extra2",
  67. intval(local_user())
  68. );
  69. $contact_count = (int) $r[0]['c'];
  70. } elseif ($type == 'm') {
  71. // autocomplete for Private Messages
  72. $r = q("SELECT COUNT(*) AS c FROM `contact`
  73. WHERE `uid` = %d AND NOT `self` AND NOT `deleted`
  74. AND NOT `blocked` AND NOT `pending` AND NOT `archive`
  75. AND `success_update` >= `failure_update`
  76. AND `network` IN ('%s', '%s', '%s') $sql_extra2",
  77. intval(local_user()),
  78. DBA::escape(Protocol::ACTIVITYPUB),
  79. DBA::escape(Protocol::DFRN),
  80. DBA::escape(Protocol::DIASPORA)
  81. );
  82. $contact_count = (int) $r[0]['c'];
  83. } elseif ($type == 'a') {
  84. // autocomplete for Contacts
  85. $r = q("SELECT COUNT(*) AS c FROM `contact`
  86. WHERE `uid` = %d AND NOT `self`
  87. AND NOT `pending` AND NOT `deleted` $sql_extra2",
  88. intval(local_user())
  89. );
  90. $contact_count = (int) $r[0]['c'];
  91. }
  92. $tot = $group_count + $contact_count;
  93. $groups = [];
  94. $contacts = [];
  95. if ($type == '' || $type == 'g') {
  96. /// @todo We should cache this query.
  97. // This can be done when we can delete cache entries via wildcard
  98. $r = q("SELECT `group`.`id`, `group`.`name`, GROUP_CONCAT(DISTINCT `group_member`.`contact-id` SEPARATOR ',') AS uids
  99. FROM `group`
  100. INNER JOIN `group_member` ON `group_member`.`gid`=`group`.`id`
  101. WHERE NOT `group`.`deleted` AND `group`.`uid` = %d
  102. $sql_extra
  103. GROUP BY `group`.`name`, `group`.`id`
  104. ORDER BY `group`.`name`
  105. LIMIT %d,%d",
  106. intval(local_user()),
  107. intval($start),
  108. intval($count)
  109. );
  110. foreach ($r as $g) {
  111. $groups[] = [
  112. 'type' => 'g',
  113. 'photo' => 'images/twopeople.png',
  114. 'name' => htmlspecialchars($g['name']),
  115. 'id' => intval($g['id']),
  116. 'uids' => array_map('intval', explode(',', $g['uids'])),
  117. 'link' => '',
  118. 'forum' => '0'
  119. ];
  120. }
  121. if ((count($groups) > 0) && ($search == '')) {
  122. $groups[] = ['separator' => true];
  123. }
  124. }
  125. $r = [];
  126. if ($type == '') {
  127. $r = q("SELECT `id`, `name`, `nick`, `micro`, `network`, `url`, `attag`, `addr`, `forum`, `prv`, (`prv` OR `forum`) AS `frm` FROM `contact`
  128. WHERE `uid` = %d AND NOT `self` AND NOT `deleted` AND NOT `blocked` AND NOT `pending` AND NOT `archive` AND `notify` != ''
  129. AND `success_update` >= `failure_update` AND NOT (`network` IN ('%s', '%s'))
  130. $sql_extra2
  131. ORDER BY `name` ASC ",
  132. intval(local_user()),
  133. DBA::escape(Protocol::OSTATUS),
  134. DBA::escape(Protocol::STATUSNET)
  135. );
  136. } elseif ($type == 'c') {
  137. $r = q("SELECT `id`, `name`, `nick`, `micro`, `network`, `url`, `attag`, `addr`, `forum`, `prv` FROM `contact`
  138. WHERE `uid` = %d AND NOT `self` AND NOT `deleted` AND NOT `blocked` AND NOT `pending` AND NOT `archive` AND `notify` != ''
  139. AND `success_update` >= `failure_update` AND NOT (`network` IN ('%s'))
  140. $sql_extra2
  141. ORDER BY `name` ASC ",
  142. intval(local_user()),
  143. DBA::escape(Protocol::STATUSNET)
  144. );
  145. } elseif ($type == 'f') {
  146. $r = q("SELECT `id`, `name`, `nick`, `micro`, `network`, `url`, `attag`, `addr`, `forum`, `prv` FROM `contact`
  147. WHERE `uid` = %d AND NOT `self` AND NOT `deleted` AND NOT `blocked` AND NOT `pending` AND NOT `archive` AND `notify` != ''
  148. AND `success_update` >= `failure_update` AND NOT (`network` IN ('%s'))
  149. AND (`forum` OR `prv`)
  150. $sql_extra2
  151. ORDER BY `name` ASC ",
  152. intval(local_user()),
  153. DBA::escape(Protocol::STATUSNET)
  154. );
  155. } elseif ($type == 'm') {
  156. $r = q("SELECT `id`, `name`, `nick`, `micro`, `network`, `url`, `attag`, `addr` FROM `contact`
  157. WHERE `uid` = %d AND NOT `self` AND NOT `deleted` AND NOT `blocked` AND NOT `pending` AND NOT `archive`
  158. AND `success_update` >= `failure_update` AND `network` IN ('%s', '%s', '%s')
  159. $sql_extra2
  160. ORDER BY `name` ASC ",
  161. intval(local_user()),
  162. DBA::escape(Protocol::ACTIVITYPUB),
  163. DBA::escape(Protocol::DFRN),
  164. DBA::escape(Protocol::DIASPORA)
  165. );
  166. } elseif ($type == 'a') {
  167. $r = q("SELECT `id`, `name`, `nick`, `micro`, `network`, `url`, `attag`, `addr`, `forum`, `prv` FROM `contact`
  168. WHERE `uid` = %d AND NOT `deleted` AND NOT `pending` AND `success_update` >= `failure_update`
  169. $sql_extra2
  170. ORDER BY `name` ASC ",
  171. intval(local_user())
  172. );
  173. } elseif ($type == 'x') {
  174. // autocomplete for global contact search (e.g. navbar search)
  175. $search = Strings::escapeTags(trim($_REQUEST['search']));
  176. $mode = $_REQUEST['smode'];
  177. $r = ACL::contactAutocomplete($search, $mode);
  178. $contacts = [];
  179. foreach ($r as $g) {
  180. $contacts[] = [
  181. 'photo' => ProxyUtils::proxifyUrl($g['photo'], false, ProxyUtils::SIZE_MICRO),
  182. 'name' => htmlspecialchars($g['name']),
  183. 'nick' => defaults($g, 'addr', $g['url']),
  184. 'network' => $g['network'],
  185. 'link' => $g['url'],
  186. 'forum' => !empty($g['community']) ? 1 : 0,
  187. ];
  188. }
  189. $o = [
  190. 'start' => $start,
  191. 'count' => $count,
  192. 'items' => $contacts,
  193. ];
  194. echo json_encode($o);
  195. exit;
  196. }
  197. if (DBA::isResult($r)) {
  198. $forums = [];
  199. foreach ($r as $g) {
  200. $entry = [
  201. 'type' => 'c',
  202. 'photo' => ProxyUtils::proxifyUrl($g['micro'], false, ProxyUtils::SIZE_MICRO),
  203. 'name' => htmlspecialchars($g['name']),
  204. 'id' => intval($g['id']),
  205. 'network' => $g['network'],
  206. 'link' => $g['url'],
  207. 'nick' => htmlentities(defaults($g, 'attag', $g['nick'])),
  208. 'addr' => htmlentities(defaults($g, 'addr', $g['url'])),
  209. 'forum' => !empty($g['forum']) || !empty($g['prv']) ? 1 : 0,
  210. ];
  211. if ($entry['forum']) {
  212. $forums[] = $entry;
  213. } else {
  214. $contacts[] = $entry;
  215. }
  216. }
  217. if (count($forums) > 0) {
  218. if ($search == '') {
  219. $forums[] = ['separator' => true];
  220. }
  221. $contacts = array_merge($forums, $contacts);
  222. }
  223. }
  224. $items = array_merge($groups, $contacts);
  225. if ($conv_id) {
  226. // In multi threaded posts the conv_id is not the parent of the whole thread
  227. $parent_item = Item::selectFirst(['parent'], ['id' => $conv_id]);
  228. if (DBA::isResult($parent_item)) {
  229. $conv_id = $parent_item['parent'];
  230. }
  231. /*
  232. * if $conv_id is set, get unknown contacts in thread
  233. * but first get known contacts url to filter them out
  234. */
  235. $known_contacts = array_map(function ($i) {
  236. return $i['link'];
  237. }, $contacts);
  238. $unknown_contacts = [];
  239. $condition = ["`parent` = ?", $conv_id];
  240. $params = ['order' => ['author-name' => true]];
  241. $authors = Item::selectForUser(local_user(), ['author-link'], $condition, $params);
  242. $item_authors = [];
  243. while ($author = Item::fetch($authors)) {
  244. $item_authors[$author['author-link']] = $author['author-link'];
  245. }
  246. DBA::close($authors);
  247. foreach ($item_authors as $author) {
  248. if (in_array($author, $known_contacts)) {
  249. continue;
  250. }
  251. $contact = Contact::getDetailsByURL($author);
  252. if (count($contact) > 0) {
  253. $unknown_contacts[] = [
  254. 'type' => 'c',
  255. 'photo' => ProxyUtils::proxifyUrl($contact['micro'], false, ProxyUtils::SIZE_MICRO),
  256. 'name' => htmlspecialchars($contact['name']),
  257. 'id' => intval($contact['cid']),
  258. 'network' => $contact['network'],
  259. 'link' => $contact['url'],
  260. 'nick' => htmlentities(defaults($contact, 'nick', $contact['addr'])),
  261. 'addr' => htmlentities(defaults($contact, 'addr', $contact['url'])),
  262. 'forum' => $contact['forum']
  263. ];
  264. }
  265. }
  266. $items = array_merge($items, $unknown_contacts);
  267. $tot += count($unknown_contacts);
  268. }
  269. $results = [
  270. 'tot' => $tot,
  271. 'start' => $start,
  272. 'count' => $count,
  273. 'groups' => $groups,
  274. 'contacts' => $contacts,
  275. 'items' => $items,
  276. 'type' => $type,
  277. 'search' => $search,
  278. ];
  279. Hook::callAll('acl_lookup_end', $results);
  280. $o = [
  281. 'tot' => $results['tot'],
  282. 'start' => $results['start'],
  283. 'count' => $results['count'],
  284. 'items' => $results['items'],
  285. ];
  286. echo json_encode($o);
  287. exit;
  288. }