PageRenderTime 56ms CodeModel.GetById 33ms RepoModel.GetById 1ms app.codeStats 0ms

/controllers/ETMembersController.class.php

https://github.com/Ramir1/esoTalk
PHP | 302 lines | 171 code | 57 blank | 74 comment | 32 complexity | 3ea5acf9cb1ff64dc37e2492e9e5debd MD5 | raw file
Possible License(s): GPL-2.0
  1. <?php
  2. // Copyright 2011 Toby Zerner, Simon Zerner
  3. // This file is part of esoTalk. Please see the included license file for usage information.
  4. if (!defined("IN_ESOTALK")) exit;
  5. /**
  6. * The members controller handles the member list, online members sheet, and the creation of new members.
  7. *
  8. * @package esoTalk
  9. */
  10. class ETMembersController extends ETController {
  11. /**
  12. * Show the member list page.
  13. *
  14. * @param string $orderBy What to sort the members by.
  15. * @param mixed $start Where to start the results from. This can be:
  16. * - An integer, in which case it will be used as a numerical offset.
  17. * - pX, where X is the "page" number.
  18. * - A letter to start from, if $orderBy is "name".
  19. * @return void
  20. */
  21. public function index($orderBy = false, $start = 0)
  22. {
  23. // Check if we have permission to view the member list.
  24. if (!C("esoTalk.members.visibleToGuests") and !ET::$session->user) {
  25. $this->render404(T("message.pageNotFound"));
  26. return false;
  27. }
  28. // Begin constructing a query to fetch results.
  29. $sql = ET::SQL()->from("member m");
  30. // If we've limited results by a search string...
  31. if ($searchString = R("search")) {
  32. // Get an array of all groups which we can possibly filter by.
  33. $groups = ET::groupModel()->getAll();
  34. $groups[GROUP_ID_ADMINISTRATOR] = array("name" => ACCOUNT_ADMINISTRATOR);
  35. $groups[GROUP_ID_MEMBER] = array("name" => ACCOUNT_MEMBER);
  36. $groups[GROUP_ID_GUEST] = array("name" => ACCOUNT_SUSPENDED);
  37. // If the search string matches any group names, then we'll filter members by their account/group.
  38. $restrictGroup = false;
  39. $search = strtolower($searchString);
  40. foreach ($groups as $id => $group) {
  41. $name = $group["name"];
  42. if (strtolower(T("group.$name", $name)) == $search or strtolower(T("group.$name.plural", $name)) == $search) {
  43. $restrictGroup = $id;
  44. break;
  45. }
  46. }
  47. // Did we find any matching groups just before? If so, add a WHERE condition to the query to filter by group.
  48. if ($restrictGroup) {
  49. if ($restrictGroup < 0) $sql->where("account", $groups[$restrictGroup]["name"]);
  50. else $sql
  51. ->from("member_group mg", "mg.memberId=m.memberId", "left")
  52. ->where("mg.groupId", $restrictGroup);
  53. }
  54. // If there were no matching groups, just perform a normal LIKE search.
  55. else $sql
  56. ->where("username LIKE :search")
  57. ->bind(":search", $searchString."%");
  58. }
  59. // Create a query to get the total number of results. Clone the results one to retain the same WHERE conditions.
  60. $count = clone $sql;
  61. $count = $count
  62. ->select("COUNT(m.memberId)")
  63. ->exec()
  64. ->result();
  65. // Make an array of possible orders for the list.
  66. $orders = array(
  67. "name" => array(T("Name"), "username ASC"),
  68. "posts" => array(T("Posts"), "countPosts DESC"),
  69. "activity" => array(T("Last active"), "lastActionTime DESC")
  70. );
  71. // If an invalid orderBy key was provided, just use the first one.
  72. if (!isset($orders[$orderBy])) $orderBy = reset(array_keys($orders));
  73. // Work out where to start the results from.
  74. $page = 0;
  75. if ($start) {
  76. // If we're ordering by name and the start argument is a single letter...
  77. if ($orderBy == "name" and strlen($start) == 1 and ctype_alpha($start)) {
  78. // Run a query to get the position of the first member starting with this letter.
  79. $start = ET::SQL()
  80. ->select("COUNT(memberId)", "position")
  81. ->from("member")
  82. ->where("STRCMP(username, :username) = -1")
  83. ->bind(":username", $start)
  84. ->exec()
  85. ->result();
  86. $start = min($count - C("esoTalk.members.membersPerPage"), $start);
  87. }
  88. // If the start argument is "pX", where X is the page number...
  89. elseif ($start[0] == "p") {
  90. $page = ltrim($start, "p");
  91. $start = C("esoTalk.members.membersPerPage") * ($page - 1);
  92. }
  93. // Otherwise, parse the start argument as a simple integer offset.
  94. else {
  95. $start = (int)($start);
  96. $page = round($start / C("esoTalk.members.membersPerPage"));
  97. }
  98. // Apply the offset to the query.
  99. $start = max(0, $start);
  100. $sql->offset($start);
  101. }
  102. // Finish constructing the query. We want to get a list of member IDs to show as the results.
  103. $ids = $sql
  104. ->select("m.memberId")
  105. ->limit(C("esoTalk.members.membersPerPage"))
  106. ->orderBy($orders[$orderBy][1])
  107. ->exec()
  108. ->allRows();
  109. foreach ($ids as &$id) $id = $id["memberId"];
  110. // Finally, fetch the member data for the members with these IDs.
  111. if ($ids) $members = ET::memberModel()->getByIds($ids);
  112. else $members = array();
  113. // If we're doing a normal page load...
  114. if ($this->responseType === RESPONSE_TYPE_DEFAULT) {
  115. // Set the title and make sure this page isn't indexed.
  116. $this->title = T("Member List");
  117. $this->addToHead("<meta name='robots' content='noindex, noarchive'/>");
  118. // Work out the canonical URL for this page.
  119. $url = "members/$orderBy/p$page";
  120. $this->canonicalURL = URL($url, true);
  121. $this->pushNavigation("members", "members", URL($url));
  122. // Add JavaScript files and variables for the page to use.
  123. $this->addJSFile("js/scrubber.js");
  124. $this->addJSFile("js/members.js");
  125. $this->addJSVar("membersPerPage", C("esoTalk.members.membersPerPage"));
  126. $this->addJSVar("countMembers", $count);
  127. $this->addJSVar("startFrom", $start);
  128. $this->addJSVar("searchString", $searchString);
  129. $this->addJSVar("orderBy", $orderBy);
  130. }
  131. // Pass data to the view.
  132. $this->data("members", $members);
  133. $this->data("countMembers", $count);
  134. $this->data("startFrom", $start);
  135. $this->data("searchString", $searchString);
  136. $this->data("orders", $orders);
  137. $this->data("orderBy", $orderBy);
  138. // On an AJAX request, just render the list, and also pass back the startFrom position.
  139. if ($this->responseType === RESPONSE_TYPE_AJAX) {
  140. $this->json("startFrom", $start);
  141. $this->render("members/list");
  142. }
  143. else $this->render("members/index");
  144. }
  145. /**
  146. * Show the "create member" sheet, containing a form to create a new member.
  147. *
  148. * @return void
  149. */
  150. public function create()
  151. {
  152. // Non-admins can't do this! Suckers.
  153. if (!ET::$session->isAdmin()) return;
  154. // Set up the form.
  155. $form = ETFactory::make("form");
  156. $form->action = URL("members/create");
  157. // Was the cancel button pressed?
  158. if ($form->isPostBack("cancel"))
  159. $this->redirect(URL(R("return", "members")));
  160. // Was the "create" button pressed?
  161. if ($form->validPostBack("submit")) {
  162. // Make sure the passwords match.
  163. if ($form->getValue("confirm") != $form->getValue("password"))
  164. $form->error("confirm", T("message.passwordsDontMatch"));
  165. // If there were no preliminary errors, proceed to attempt to create the member with the model.
  166. if (!$form->errorCount()) {
  167. $data = array(
  168. "username" => $form->getValue("username"),
  169. "email" => $form->getValue("email"),
  170. "password" => $form->getValue("password"),
  171. "account" => ACCOUNT_MEMBER,
  172. "confirmedEmail" => true
  173. );
  174. $model = ET::memberModel();
  175. $id = $model->create($data);
  176. // If there were any errors, pass them back to the form.
  177. if ($model->errorCount()) $form->errors($model->errors());
  178. // Otherwise, redirect to this new member's profile.
  179. else $this->redirect(URL(memberURL($id, $form->getValue("username"))));
  180. }
  181. }
  182. $this->data("form", $form);
  183. $this->render("members/create");
  184. }
  185. /**
  186. * Show the "online members" sheet.
  187. *
  188. * @return void
  189. */
  190. public function online()
  191. {
  192. // Check if we have permission to view the online list.
  193. if (!C("esoTalk.members.visibleToGuests") and !ET::$session->user) {
  194. $this->render404(T("message.pageNotFound"));
  195. return false;
  196. }
  197. // Set the title and make sure this page isn't indexed.
  198. $this->title = T("Online Members");
  199. $this->addToHead("<meta name='robots' content='noindex, noarchive'/>");
  200. // Construct a query to get only members who are online.
  201. $sql = ET::SQL()
  202. ->where((time() - ET::config("esoTalk.userOnlineExpire"))."<lastActionTime")
  203. ->orderBy("lastActionTime DESC");
  204. // Pass this query to the member model and get all of these members' data.
  205. $members = ET::memberModel()->getWithSQL($sql);
  206. $this->data("members", $members);
  207. $this->render("members/online");
  208. }
  209. /**
  210. * Return a JSON array of up to 50 members whose usernames match a given string. This data can be used to
  211. * create a list of members in an autocomplete menu.
  212. *
  213. * @param string $input The string to match member usernames against.
  214. * @return void
  215. */
  216. public function autocomplete($input = "")
  217. {
  218. // Force the response type to JSON.
  219. $this->responseType = RESPONSE_TYPE_JSON;
  220. // Don't do this for strings less than three characters for performance reasons.
  221. if (strlen($input) < 3) return;
  222. // Construct a query to fetch matching members.
  223. $results = ET::SQL()
  224. ->select("'member' AS type")
  225. ->select("memberId AS id")
  226. ->select("username AS name")
  227. ->select("avatarFormat")
  228. ->select("email")
  229. ->from("member")
  230. ->where("username LIKE :username")
  231. ->bind(":username", $input."%")
  232. ->orderBy("username")
  233. ->limit(50)
  234. ->exec()
  235. ->allRows();
  236. // Loop through the results and generate avatar HTML for each one.
  237. foreach ($results as $k => $v) {
  238. $results[$k]["avatar"] = avatar($v, "thumb");
  239. unset($results[$k]["avatarFormat"]);
  240. unset($results[$k]["email"]);
  241. }
  242. $this->json("results", $results);
  243. $this->render();
  244. }
  245. }