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.5 KiB

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