groupdirectory.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379
  1. <?php
  2. /**
  3. * StatusNet, the distributed open-source microblogging tool
  4. *
  5. * Output a group directory
  6. *
  7. * PHP version 5
  8. *
  9. * LICENCE: This program is free software: you can redistribute it and/or modify
  10. * it under the terms of the GNU Affero General Public License as published by
  11. * the Free Software Foundation, either version 3 of the License, or
  12. * (at your option) any later version.
  13. *
  14. * This program is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. * GNU Affero General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU Affero General Public License
  20. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  21. *
  22. * @category Public
  23. * @package StatusNet
  24. * @author Zach Copley <zach@status.net>
  25. * @copyright 2011 StatusNet, Inc.
  26. * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
  27. * @link http://status.net/
  28. */
  29. if (!defined('GNUSOCIAL')) {
  30. exit(1);
  31. }
  32. /**
  33. * Group directory
  34. *
  35. * @category Directory
  36. * @package StatusNet
  37. * @author Zach Copley <zach@status.net>
  38. * @author Mikael Nordfeldth <mmn@hethane.se>
  39. * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
  40. * @link http://status.net/
  41. */
  42. class GroupdirectoryAction extends ManagedAction
  43. {
  44. protected $redirectAfterLogin = true;
  45. /**
  46. * The page we're on
  47. *
  48. * @var integer
  49. */
  50. public $page;
  51. /**
  52. * What to filter the search results by
  53. *
  54. * @var string
  55. */
  56. public $filter;
  57. /**
  58. * Column to sort by
  59. *
  60. * @var string
  61. */
  62. public $sort;
  63. /**
  64. * How to order search results, ascending or descending
  65. *
  66. * @var string
  67. */
  68. public $reverse;
  69. /**
  70. * Query
  71. *
  72. * @var string
  73. */
  74. public $q;
  75. /**
  76. * Title of the page
  77. *
  78. * @return string Title of the page
  79. */
  80. public function title()
  81. {
  82. // @fixme: This looks kinda gross
  83. if ($this->filter == 'all') {
  84. if ($this->page != 1) {
  85. // TRANS: Title for group directory page. %d is a page number.
  86. return(sprintf(_m('Group Directory, page %d'), $this->page));
  87. }
  88. // TRANS: Title for group directory page.
  89. return _m('Group directory');
  90. } elseif ($this->page == 1) {
  91. return sprintf(
  92. // TRANS: Title for group directory page when it is filtered.
  93. // TRANS: %s is the filter string.
  94. _m('Group directory - %s'),
  95. strtoupper($this->filter)
  96. );
  97. } else {
  98. return sprintf(
  99. // TRANS: Title for group directory page when it is filtered.
  100. // TRANS: %1$s is the filter string, %2$d is a page number.
  101. _m('Group directory - %1$s, page %2$d'),
  102. strtoupper($this->filter),
  103. $this->page
  104. );
  105. }
  106. }
  107. /**
  108. * Instructions for use
  109. *
  110. * @return instructions for use
  111. */
  112. public function getInstructions()
  113. {
  114. // TRANS: Page instructions.
  115. return _m("After you join a group you can send messages to all other members\n".
  116. "using the syntax \"!groupname\".\n\n".
  117. "Browse groups, or search for groups by their name, location or topic.\n".
  118. "Separate the terms by spaces; they must be three characters or more.") . "\n";
  119. }
  120. /**
  121. * Is this page read-only?
  122. *
  123. * @return boolean true
  124. */
  125. public function isReadOnly($args)
  126. {
  127. return true;
  128. }
  129. protected function doPreparation()
  130. {
  131. $this->page = ($this->arg('page')) ? ($this->arg('page') + 0) : 1;
  132. $this->filter = $this->arg('filter', 'all');
  133. $this->reverse = $this->boolean('reverse');
  134. $this->q = $this->trimmed('q');
  135. $this->sort = $this->arg('sort', 'nickname');
  136. }
  137. /**
  138. * Show the page notice
  139. *
  140. * Shows instructions for the page
  141. *
  142. * @return void
  143. */
  144. public function showPageNotice()
  145. {
  146. $instr = $this->getInstructions();
  147. $output = common_markup_to_html($instr);
  148. $this->elementStart('div', 'instructions');
  149. $this->raw($output);
  150. $this->elementEnd('div');
  151. }
  152. /**
  153. * Content area
  154. *
  155. * Shows the groups
  156. *
  157. * @return void
  158. */
  159. public function showContent()
  160. {
  161. if (common_logged_in()) {
  162. $this->elementStart('p',
  163. ['id' => 'new_group']);
  164. $this->element('a',
  165. ['href' => common_local_url('newgroup'),
  166. 'class' => 'more'],
  167. // TRANS: Link to create a new group on the group list page.
  168. _m('Create a new group'));
  169. $this->elementEnd('p');
  170. }
  171. $this->showForm();
  172. $this->elementStart('div', ['id' => 'profile_directory']);
  173. // @todo FIXME: Does "All" need i18n here?
  174. $alphaNav = new AlphaNav($this, false, false, ['0-9', 'All']);
  175. $alphaNav->show();
  176. $group = null;
  177. $group = $this->getGroups();
  178. $cnt = 0;
  179. if (!empty($group)) {
  180. $groupList = new SortableGroupList(
  181. $group,
  182. common_current_user(),
  183. $this
  184. );
  185. $cnt = $groupList->show();
  186. $group->free();
  187. if (0 == $cnt) {
  188. $this->showEmptyListMessage();
  189. }
  190. }
  191. $args = [];
  192. if (isset($this->q)) {
  193. $args['q'] = $this->q;
  194. } else {
  195. $args['filter'] = $this->filter;
  196. }
  197. $this->pagination(
  198. $this->page > 1,
  199. $cnt > PROFILES_PER_PAGE,
  200. $this->page,
  201. 'groupdirectory',
  202. $args
  203. );
  204. $this->elementEnd('div');
  205. }
  206. public function showForm($error=null)
  207. {
  208. $this->elementStart('form',
  209. ['method' => 'get',
  210. 'id' => 'form_search',
  211. 'class' => 'form_settings',
  212. 'action' => common_local_url('groupdirectory')]);
  213. $this->elementStart('fieldset');
  214. // TRANS: Fieldset legend.
  215. $this->element('legend', null, _m('Search groups'));
  216. $this->elementStart('ul', 'form_data');
  217. $this->elementStart('li');
  218. // TRANS: Field label for input of one or more keywords.
  219. $this->input('q', _m('Keyword(s)'), $this->q);
  220. // TRANS: Button text for searching group directory.
  221. $this->submit('search', _m('BUTTON', 'Search'));
  222. $this->elementEnd('li');
  223. $this->elementEnd('ul');
  224. $this->elementEnd('fieldset');
  225. $this->elementEnd('form');
  226. }
  227. /*
  228. * Get groups filtered by the current filter, sort key,
  229. * sort order, and page
  230. */
  231. public function getGroups()
  232. {
  233. $group = new User_group();
  234. // Disable this to get global group searches
  235. $group->joinAdd(['id', 'local_group:group_id']);
  236. $order = false;
  237. if (!empty($this->q)) {
  238. $wheres = ['nickname', 'fullname', 'homepage', 'description', 'location'];
  239. foreach ($wheres as $where) {
  240. // Double % because of sprintf
  241. $group->whereAdd(sprintf('LOWER(%1$s.%2$s) LIKE LOWER("%%%3$s%%")',
  242. $group->escapedTableName(),
  243. $where,
  244. $group->escape($this->q)),
  245. 'OR');
  246. }
  247. $order = sprintf('%1$s.%2$s %3$s',
  248. $group->escapedTableName(),
  249. $this->getSortKey('created'),
  250. $this->reverse ? 'DESC' : 'ASC');
  251. } else {
  252. // User is browsing via AlphaNav
  253. switch ($this->filter) {
  254. case 'all':
  255. // NOOP
  256. break;
  257. case '0-9':
  258. $group->whereAdd(sprintf('LEFT(%1$s.%2$s, 1) BETWEEN %3$s AND %4$s',
  259. $group->escapedTableName(),
  260. 'nickname',
  261. $group->_quote("0"),
  262. $group->_quote("9")));
  263. break;
  264. default:
  265. $group->whereAdd(sprintf('LEFT(LOWER(%1$s.%2$s), 1) = %3$s',
  266. $group->escapedTableName(),
  267. 'nickname',
  268. $group->_quote($this->filter)));
  269. }
  270. $order = sprintf('%1$s.%2$s %3$s, %1$s.%4$s ASC',
  271. $group->escapedTableName(),
  272. $this->getSortKey('nickname'),
  273. $this->reverse ? 'DESC' : 'ASC',
  274. 'nickname');
  275. }
  276. $offset = ($this->page-1) * PROFILES_PER_PAGE;
  277. $limit = PROFILES_PER_PAGE + 1;
  278. $group->selectAdd();
  279. $group->selectAdd('profile_id');
  280. $group->orderBy($order);
  281. $group->limit($offset, $limit);
  282. $group->find();
  283. return Profile::multiGet('id', $group->fetchAll('profile_id'));
  284. }
  285. /**
  286. * Filter the sort parameter
  287. *
  288. * @return string a column name for sorting
  289. */
  290. public function getSortKey($def='created')
  291. {
  292. switch ($this->sort) {
  293. case 'nickname':
  294. case 'created':
  295. return $this->sort;
  296. default:
  297. return $def;
  298. }
  299. }
  300. /**
  301. * Show a nice message when there's no search results
  302. */
  303. public function showEmptyListMessage()
  304. {
  305. if (!empty($this->filter) && ($this->filter != 'all')) {
  306. $this->element('p',
  307. 'error',
  308. sprintf(
  309. // TRANS: Empty list message for searching group directory.
  310. // TRANS: %s is the search string.
  311. _m('No groups starting with %s.'),
  312. $this->filter));
  313. } else {
  314. // TRANS: Empty list message for searching group directory.
  315. $this->element('p', 'error', _m('No results.'));
  316. // TRANS: Help text for searching group directory.
  317. $message = _m("* Make sure all words are spelled correctly.\n".
  318. "* Try different keywords.\n".
  319. "* Try more general keywords.\n".
  320. "* Try fewer keywords.");
  321. $this->elementStart('div', 'help instructions');
  322. $this->raw(common_markup_to_html($message));
  323. $this->elementEnd('div');
  324. }
  325. }
  326. public function showSections()
  327. {
  328. $gbp = new GroupsByPostsSection($this);
  329. $gbp->show();
  330. $gbm = new GroupsByMembersSection($this);
  331. $gbm->show();
  332. }
  333. }