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.
 
 
 
 
 
 

246 lines
7.4 KiB

  1. <?php
  2. /**
  3. * @file mod/community.php
  4. */
  5. use Friendica\App;
  6. use Friendica\Content\Feature;
  7. use Friendica\Content\Nav;
  8. use Friendica\Content\Pager;
  9. use Friendica\Content\Widget\TrendingTags;
  10. use Friendica\Core\ACL;
  11. use Friendica\Core\Config;
  12. use Friendica\Core\L10n;
  13. use Friendica\Core\Renderer;
  14. use Friendica\Core\Session;
  15. use Friendica\Database\DBA;
  16. use Friendica\DI;
  17. use Friendica\Model\Item;
  18. use Friendica\Model\User;
  19. function community_content(App $a, $update = 0)
  20. {
  21. $o = '';
  22. if (Config::get('system', 'block_public') && !Session::isAuthenticated()) {
  23. notice(L10n::t('Public access denied.') . EOL);
  24. return;
  25. }
  26. $page_style = Config::get('system', 'community_page_style');
  27. if ($page_style == CP_NO_INTERNAL_COMMUNITY) {
  28. notice(L10n::t('Access denied.') . EOL);
  29. return;
  30. }
  31. $accounttype = null;
  32. if ($a->argc > 2) {
  33. switch ($a->argv[2]) {
  34. case 'person':
  35. $accounttype = User::ACCOUNT_TYPE_PERSON;
  36. break;
  37. case 'organisation':
  38. $accounttype = User::ACCOUNT_TYPE_ORGANISATION;
  39. break;
  40. case 'news':
  41. $accounttype = User::ACCOUNT_TYPE_NEWS;
  42. break;
  43. case 'community':
  44. $accounttype = User::ACCOUNT_TYPE_COMMUNITY;
  45. break;
  46. }
  47. }
  48. if ($a->argc > 1) {
  49. $content = $a->argv[1];
  50. } else {
  51. if (!empty(Config::get('system', 'singleuser'))) {
  52. // On single user systems only the global page does make sense
  53. $content = 'global';
  54. } else {
  55. // When only the global community is allowed, we use this as default
  56. $content = $page_style == CP_GLOBAL_COMMUNITY ? 'global' : 'local';
  57. }
  58. }
  59. if (!in_array($content, ['local', 'global'])) {
  60. notice(L10n::t('Community option not available.') . EOL);
  61. return;
  62. }
  63. // Check if we are allowed to display the content to visitors
  64. if (!local_user()) {
  65. $available = $page_style == CP_USERS_AND_GLOBAL;
  66. if (!$available) {
  67. $available = ($page_style == CP_USERS_ON_SERVER) && ($content == 'local');
  68. }
  69. if (!$available) {
  70. $available = ($page_style == CP_GLOBAL_COMMUNITY) && ($content == 'global');
  71. }
  72. if (!$available) {
  73. notice(L10n::t('Not available.') . EOL);
  74. return;
  75. }
  76. }
  77. if (!$update) {
  78. $tabs = [];
  79. if ((local_user() || in_array($page_style, [CP_USERS_AND_GLOBAL, CP_USERS_ON_SERVER])) && empty(Config::get('system', 'singleuser'))) {
  80. $tabs[] = [
  81. 'label' => L10n::t('Local Community'),
  82. 'url' => 'community/local',
  83. 'sel' => $content == 'local' ? 'active' : '',
  84. 'title' => L10n::t('Posts from local users on this server'),
  85. 'id' => 'community-local-tab',
  86. 'accesskey' => 'l'
  87. ];
  88. }
  89. if (local_user() || in_array($page_style, [CP_USERS_AND_GLOBAL, CP_GLOBAL_COMMUNITY])) {
  90. $tabs[] = [
  91. 'label' => L10n::t('Global Community'),
  92. 'url' => 'community/global',
  93. 'sel' => $content == 'global' ? 'active' : '',
  94. 'title' => L10n::t('Posts from users of the whole federated network'),
  95. 'id' => 'community-global-tab',
  96. 'accesskey' => 'g'
  97. ];
  98. }
  99. $tab_tpl = Renderer::getMarkupTemplate('common_tabs.tpl');
  100. $o .= Renderer::replaceMacros($tab_tpl, ['$tabs' => $tabs]);
  101. Nav::setSelected('community');
  102. // We need the editor here to be able to reshare an item.
  103. if (local_user()) {
  104. $x = [
  105. 'is_owner' => true,
  106. 'allow_location' => $a->user['allow_location'],
  107. 'default_location' => $a->user['default-location'],
  108. 'nickname' => $a->user['nickname'],
  109. 'lockstate' => (is_array($a->user) && (strlen($a->user['allow_cid']) || strlen($a->user['allow_gid']) || strlen($a->user['deny_cid']) || strlen($a->user['deny_gid'])) ? 'lock' : 'unlock'),
  110. 'acl' => ACL::getFullSelectorHTML(DI::page(), $a->user, true),
  111. 'bang' => '',
  112. 'visitor' => 'block',
  113. 'profile_uid' => local_user(),
  114. ];
  115. $o .= status_editor($a, $x, 0, true);
  116. }
  117. }
  118. // check if we serve a mobile device and get the user settings accordingly
  119. if (DI::mode()->isMobile()) {
  120. $itemspage_network = DI::pConfig()->get(local_user(), 'system', 'itemspage_mobile_network', 20);
  121. } else {
  122. $itemspage_network = DI::pConfig()->get(local_user(), 'system', 'itemspage_network', 40);
  123. }
  124. // now that we have the user settings, see if the theme forces
  125. // a maximum item number which is lower then the user choice
  126. if (($a->force_max_items > 0) && ($a->force_max_items < $itemspage_network)) {
  127. $itemspage_network = $a->force_max_items;
  128. }
  129. $pager = new Pager(DI::args()->getQueryString(), $itemspage_network);
  130. $r = community_getitems($pager->getStart(), $pager->getItemsPerPage(), $content, $accounttype);
  131. if (!DBA::isResult($r)) {
  132. info(L10n::t('No results.') . EOL);
  133. return $o;
  134. }
  135. $maxpostperauthor = (int) Config::get('system', 'max_author_posts_community_page');
  136. if (($maxpostperauthor != 0) && ($content == 'local')) {
  137. $count = 1;
  138. $previousauthor = "";
  139. $numposts = 0;
  140. $s = [];
  141. do {
  142. foreach ($r as $item) {
  143. if ($previousauthor == $item["author-link"]) {
  144. ++$numposts;
  145. } else {
  146. $numposts = 0;
  147. }
  148. $previousauthor = $item["author-link"];
  149. if (($numposts < $maxpostperauthor) && (count($s) < $pager->getItemsPerPage())) {
  150. $s[] = $item;
  151. }
  152. }
  153. if (count($s) < $pager->getItemsPerPage()) {
  154. $r = community_getitems($pager->getStart() + ($count * $pager->getItemsPerPage()), $pager->getItemsPerPage(), $content, $accounttype);
  155. }
  156. } while ((count($s) < $pager->getItemsPerPage()) && ( ++$count < 50) && (count($r) > 0));
  157. } else {
  158. $s = $r;
  159. }
  160. $o .= conversation($a, $s, $pager, 'community', $update, false, 'commented', local_user());
  161. if (!$update) {
  162. $o .= $pager->renderMinimal(count($r));
  163. }
  164. if (empty(DI::page()['aside'])) {
  165. DI::page()['aside'] = '';
  166. }
  167. if (Feature::isEnabled(local_user(), 'trending_tags')) {
  168. DI::page()['aside'] .= TrendingTags::getHTML($content);
  169. }
  170. $t = Renderer::getMarkupTemplate("community.tpl");
  171. return Renderer::replaceMacros($t, [
  172. '$content' => $o,
  173. '$header' => '',
  174. '$show_global_community_hint' => ($content == 'global') && Config::get('system', 'show_global_community_hint'),
  175. '$global_community_hint' => L10n::t("This community stream shows all public posts received by this node. They may not reflect the opinions of this node’s users.")
  176. ]);
  177. }
  178. function community_getitems($start, $itemspage, $content, $accounttype)
  179. {
  180. if ($content == 'local') {
  181. if (!is_null($accounttype)) {
  182. $sql_accounttype = " AND `user`.`account-type` = ?";
  183. $values = [$accounttype, $start, $itemspage];
  184. } else {
  185. $sql_accounttype = "";
  186. $values = [$start, $itemspage];
  187. }
  188. /// @todo Use "unsearchable" here as well (instead of "hidewall")
  189. $r = DBA::p("SELECT `item`.`uri`, `author`.`url` AS `author-link` FROM `thread`
  190. STRAIGHT_JOIN `user` ON `user`.`uid` = `thread`.`uid` AND NOT `user`.`hidewall`
  191. STRAIGHT_JOIN `item` ON `item`.`id` = `thread`.`iid`
  192. STRAIGHT_JOIN `contact` AS `author` ON `author`.`id`=`item`.`author-id`
  193. WHERE `thread`.`visible` AND NOT `thread`.`deleted` AND NOT `thread`.`moderated`
  194. AND NOT `thread`.`private` AND `thread`.`wall` AND `thread`.`origin` $sql_accounttype
  195. ORDER BY `thread`.`commented` DESC LIMIT ?, ?", $values);
  196. return DBA::toArray($r);
  197. } elseif ($content == 'global') {
  198. if (!is_null($accounttype)) {
  199. $condition = ["`uid` = ? AND NOT `author`.`unsearchable` AND NOT `owner`.`unsearchable` AND `owner`.`contact-type` = ?", 0, $accounttype];
  200. } else {
  201. $condition = ["`uid` = ? AND NOT `author`.`unsearchable` AND NOT `owner`.`unsearchable`", 0];
  202. }
  203. $r = Item::selectThreadForUser(0, ['uri'], $condition, ['order' => ['commented' => true], 'limit' => [$start, $itemspage]]);
  204. return DBA::toArray($r);
  205. }
  206. // Should never happen
  207. return [];
  208. }