PageRenderTime 61ms CodeModel.GetById 5ms RepoModel.GetById 0ms app.codeStats 0ms

/sources/controllers/ProfileOptions.controller.php

https://github.com/Arantor/Elkarte
PHP | 1342 lines | 971 code | 154 blank | 217 comment | 169 complexity | b6a7370f390c7f18838c3a860a6eca5e MD5 | raw file
Possible License(s): BSD-3-Clause, LGPL-3.0
  1. <?php
  2. /**
  3. * @name ElkArte Forum
  4. * @copyright ElkArte Forum contributors
  5. * @license BSD http://opensource.org/licenses/BSD-3-Clause
  6. *
  7. * This software is a derived product, based on:
  8. *
  9. * Simple Machines Forum (SMF)
  10. * copyright: 2011 Simple Machines (http://www.simplemachines.org)
  11. * license: BSD, See included LICENSE.TXT for terms and conditions.
  12. *
  13. * @version 1.0 Alpha
  14. *
  15. * This file has the primary job of showing and editing people's profiles.
  16. * It also allows the user to change some of their or another's preferences,
  17. * and such things
  18. *
  19. */
  20. if (!defined('ELKARTE'))
  21. die('No access...');
  22. /**
  23. * Show all the users buddies, as well as a add/delete interface.
  24. *
  25. * @param int $memID id_member
  26. */
  27. function action_editBuddyIgnoreLists($memID)
  28. {
  29. global $context, $txt, $scripturl, $modSettings, $user_profile;
  30. // Do a quick check to ensure people aren't getting here illegally!
  31. if (!$context['user']['is_owner'] || empty($modSettings['enable_buddylist']))
  32. fatal_lang_error('no_access', false);
  33. // Can we email the user direct?
  34. $context['can_moderate_forum'] = allowedTo('moderate_forum');
  35. $context['can_send_email'] = allowedTo('send_email_to_members');
  36. $subActions = array(
  37. 'buddies' => array('action_editBuddies', $txt['editBuddies']),
  38. 'ignore' => array('action_editIgnoreList', $txt['editIgnoreList']),
  39. );
  40. $context['list_area'] = isset($_GET['sa']) && isset($subActions[$_GET['sa']]) ? $_GET['sa'] : 'buddies';
  41. // Create the tabs for the template.
  42. $context[$context['profile_menu_name']]['tab_data'] = array(
  43. 'title' => $txt['editBuddyIgnoreLists'],
  44. 'description' => $txt['buddy_ignore_desc'],
  45. 'icon' => 'profile_hd.png',
  46. 'tabs' => array(
  47. 'buddies' => array(),
  48. 'ignore' => array(),
  49. ),
  50. );
  51. // Pass on to the actual function.
  52. $subActions[$context['list_area']][0]($memID);
  53. }
  54. /**
  55. * Show all the users buddies, as well as a add/delete interface.
  56. *
  57. * @param int $memID id_member
  58. */
  59. function action_editBuddies($memID)
  60. {
  61. global $txt, $scripturl, $modSettings;
  62. global $context, $user_profile, $memberContext, $smcFunc;
  63. // We want to view what we're doing :P
  64. $context['sub_template'] = 'editBuddies';
  65. // For making changes!
  66. $buddiesArray = explode(',', $user_profile[$memID]['buddy_list']);
  67. foreach ($buddiesArray as $k => $dummy)
  68. if ($dummy == '')
  69. unset($buddiesArray[$k]);
  70. // Removing a buddy?
  71. if (isset($_GET['remove']))
  72. {
  73. checkSession('get');
  74. call_integration_hook('integrate_remove_buddy', array($memID));
  75. // Heh, I'm lazy, do it the easy way...
  76. foreach ($buddiesArray as $key => $buddy)
  77. if ($buddy == (int) $_GET['remove'])
  78. unset($buddiesArray[$key]);
  79. // Make the changes.
  80. $user_profile[$memID]['buddy_list'] = implode(',', $buddiesArray);
  81. updateMemberData($memID, array('buddy_list' => $user_profile[$memID]['buddy_list']));
  82. // Redirect off the page because we don't like all this ugly query stuff to stick in the history.
  83. redirectexit('action=profile;area=lists;sa=buddies;u=' . $memID);
  84. }
  85. elseif (isset($_POST['new_buddy']))
  86. {
  87. checkSession();
  88. // Prepare the string for extraction...
  89. $_POST['new_buddy'] = strtr($smcFunc['htmlspecialchars']($_POST['new_buddy'], ENT_QUOTES), array('&quot;' => '"'));
  90. preg_match_all('~"([^"]+)"~', $_POST['new_buddy'], $matches);
  91. $new_buddies = array_unique(array_merge($matches[1], explode(',', preg_replace('~"[^"]+"~', '', $_POST['new_buddy']))));
  92. foreach ($new_buddies as $k => $dummy)
  93. {
  94. $new_buddies[$k] = strtr(trim($new_buddies[$k]), array('\'' => '&#039;'));
  95. if (strlen($new_buddies[$k]) == 0 || in_array($new_buddies[$k], array($user_profile[$memID]['member_name'], $user_profile[$memID]['real_name'])))
  96. unset($new_buddies[$k]);
  97. }
  98. call_integration_hook('integrate_add_buddies', array($memID, $new_buddies));
  99. if (!empty($new_buddies))
  100. {
  101. // Now find out the id_member of the buddy.
  102. $request = $smcFunc['db_query']('', '
  103. SELECT id_member
  104. FROM {db_prefix}members
  105. WHERE member_name IN ({array_string:new_buddies}) OR real_name IN ({array_string:new_buddies})
  106. LIMIT {int:count_new_buddies}',
  107. array(
  108. 'new_buddies' => $new_buddies,
  109. 'count_new_buddies' => count($new_buddies),
  110. )
  111. );
  112. // Add the new member to the buddies array.
  113. while ($row = $smcFunc['db_fetch_assoc']($request))
  114. $buddiesArray[] = (int) $row['id_member'];
  115. $smcFunc['db_free_result']($request);
  116. // Now update the current users buddy list.
  117. $user_profile[$memID]['buddy_list'] = implode(',', $buddiesArray);
  118. updateMemberData($memID, array('buddy_list' => $user_profile[$memID]['buddy_list']));
  119. }
  120. // Back to the buddy list!
  121. redirectexit('action=profile;area=lists;sa=buddies;u=' . $memID);
  122. }
  123. // Get all the users "buddies"...
  124. $buddies = array();
  125. if (!empty($buddiesArray))
  126. {
  127. $result = $smcFunc['db_query']('', '
  128. SELECT id_member
  129. FROM {db_prefix}members
  130. WHERE id_member IN ({array_int:buddy_list})
  131. ORDER BY real_name
  132. LIMIT {int:buddy_list_count}',
  133. array(
  134. 'buddy_list' => $buddiesArray,
  135. 'buddy_list_count' => substr_count($user_profile[$memID]['buddy_list'], ',') + 1,
  136. )
  137. );
  138. while ($row = $smcFunc['db_fetch_assoc']($result))
  139. $buddies[] = $row['id_member'];
  140. $smcFunc['db_free_result']($result);
  141. }
  142. $context['buddy_count'] = count($buddies);
  143. // Load all the members up.
  144. loadMemberData($buddies, false, 'profile');
  145. // Setup the context for each buddy.
  146. $context['buddies'] = array();
  147. foreach ($buddies as $buddy)
  148. {
  149. loadMemberContext($buddy);
  150. $context['buddies'][$buddy] = $memberContext[$buddy];
  151. }
  152. call_integration_hook('integrate_view_buddies', array($memID));
  153. }
  154. /**
  155. * Allows the user to view their ignore list,
  156. * as well as the option to manage members on it.
  157. *
  158. * @param int $memID id_member
  159. */
  160. function action_editIgnoreList($memID)
  161. {
  162. global $txt, $scripturl, $modSettings;
  163. global $context, $user_profile, $memberContext, $smcFunc;
  164. // We want to view what we're doing :P
  165. $context['sub_template'] = 'editIgnoreList';
  166. // For making changes!
  167. $ignoreArray = explode(',', $user_profile[$memID]['pm_ignore_list']);
  168. foreach ($ignoreArray as $k => $dummy)
  169. if ($dummy == '')
  170. unset($ignoreArray[$k]);
  171. // Removing a member from the ignore list?
  172. if (isset($_GET['remove']))
  173. {
  174. checkSession('get');
  175. // Heh, I'm lazy, do it the easy way...
  176. foreach ($ignoreArray as $key => $id_remove)
  177. if ($id_remove == (int) $_GET['remove'])
  178. unset($ignoreArray[$key]);
  179. // Make the changes.
  180. $user_profile[$memID]['pm_ignore_list'] = implode(',', $ignoreArray);
  181. updateMemberData($memID, array('pm_ignore_list' => $user_profile[$memID]['pm_ignore_list']));
  182. // Redirect off the page because we don't like all this ugly query stuff to stick in the history.
  183. redirectexit('action=profile;area=lists;sa=ignore;u=' . $memID);
  184. }
  185. elseif (isset($_POST['new_ignore']))
  186. {
  187. checkSession();
  188. // Prepare the string for extraction...
  189. $_POST['new_ignore'] = strtr($smcFunc['htmlspecialchars']($_POST['new_ignore'], ENT_QUOTES), array('&quot;' => '"'));
  190. preg_match_all('~"([^"]+)"~', $_POST['new_ignore'], $matches);
  191. $new_entries = array_unique(array_merge($matches[1], explode(',', preg_replace('~"[^"]+"~', '', $_POST['new_ignore']))));
  192. foreach ($new_entries as $k => $dummy)
  193. {
  194. $new_entries[$k] = strtr(trim($new_entries[$k]), array('\'' => '&#039;'));
  195. if (strlen($new_entries[$k]) == 0 || in_array($new_entries[$k], array($user_profile[$memID]['member_name'], $user_profile[$memID]['real_name'])))
  196. unset($new_entries[$k]);
  197. }
  198. if (!empty($new_entries))
  199. {
  200. // Now find out the id_member for the members in question.
  201. $request = $smcFunc['db_query']('', '
  202. SELECT id_member
  203. FROM {db_prefix}members
  204. WHERE member_name IN ({array_string:new_entries}) OR real_name IN ({array_string:new_entries})
  205. LIMIT {int:count_new_entries}',
  206. array(
  207. 'new_entries' => $new_entries,
  208. 'count_new_entries' => count($new_entries),
  209. )
  210. );
  211. // Add the new member to the buddies array.
  212. while ($row = $smcFunc['db_fetch_assoc']($request))
  213. $ignoreArray[] = (int) $row['id_member'];
  214. $smcFunc['db_free_result']($request);
  215. // Now update the current users buddy list.
  216. $user_profile[$memID]['pm_ignore_list'] = implode(',', $ignoreArray);
  217. updateMemberData($memID, array('pm_ignore_list' => $user_profile[$memID]['pm_ignore_list']));
  218. }
  219. // Back to the list of pityful people!
  220. redirectexit('action=profile;area=lists;sa=ignore;u=' . $memID);
  221. }
  222. // Initialise the list of members we're ignoring.
  223. $ignored = array();
  224. if (!empty($ignoreArray))
  225. {
  226. $result = $smcFunc['db_query']('', '
  227. SELECT id_member
  228. FROM {db_prefix}members
  229. WHERE id_member IN ({array_int:ignore_list})
  230. ORDER BY real_name
  231. LIMIT {int:ignore_list_count}',
  232. array(
  233. 'ignore_list' => $ignoreArray,
  234. 'ignore_list_count' => substr_count($user_profile[$memID]['pm_ignore_list'], ',') + 1,
  235. )
  236. );
  237. while ($row = $smcFunc['db_fetch_assoc']($result))
  238. $ignored[] = $row['id_member'];
  239. $smcFunc['db_free_result']($result);
  240. }
  241. $context['ignore_count'] = count($ignored);
  242. // Load all the members up.
  243. loadMemberData($ignored, false, 'profile');
  244. // Setup the context for each buddy.
  245. $context['ignore_list'] = array();
  246. foreach ($ignored as $ignore_member)
  247. {
  248. loadMemberContext($ignore_member);
  249. $context['ignore_list'][$ignore_member] = $memberContext[$ignore_member];
  250. }
  251. }
  252. /**
  253. * Allows the user to see or change their account info.
  254. *
  255. * @param int $memID id_member
  256. */
  257. function action_account($memID)
  258. {
  259. global $context, $txt;
  260. // be sure we have this
  261. require_once(SUBSDIR . '/Profile.subs.php');
  262. loadThemeOptions($memID);
  263. if (allowedTo(array('profile_identity_own', 'profile_identity_any')))
  264. loadCustomFields($memID, 'account');
  265. $context['sub_template'] = 'edit_options';
  266. $context['page_desc'] = $txt['account_info'];
  267. setupProfileContext(
  268. array(
  269. 'member_name', 'real_name', 'date_registered', 'posts', 'lngfile', 'hr',
  270. 'id_group', 'hr',
  271. 'email_address', 'hide_email', 'show_online', 'hr',
  272. 'passwrd1', 'passwrd2', 'hr',
  273. 'secret_question', 'secret_answer',
  274. )
  275. );
  276. }
  277. /**
  278. * Allow the user to change the forum options in their profile.
  279. *
  280. * @param int $memID id_member
  281. */
  282. function action_forumProfile($memID)
  283. {
  284. global $context, $user_profile, $user_info, $txt, $modSettings;
  285. // make sure we have this
  286. require_once(SUBSDIR . '/Profile.subs.php');
  287. loadThemeOptions($memID);
  288. if (allowedTo(array('profile_extra_own', 'profile_extra_any')))
  289. loadCustomFields($memID, 'forumprofile');
  290. $context['sub_template'] = 'edit_options';
  291. $context['page_desc'] = $txt['forumProfile_info'];
  292. $context['show_preview_button'] = true;
  293. setupProfileContext(
  294. array(
  295. 'avatar_choice', 'hr', 'personal_text', 'hr',
  296. 'bday1', 'location', 'gender', 'hr',
  297. 'usertitle', 'signature', 'hr',
  298. 'karma_good', 'hr',
  299. 'website_title', 'website_url',
  300. )
  301. );
  302. }
  303. /**
  304. * Allow the edit of *someone elses* personal message settings.
  305. *
  306. * @param int $memID id_member
  307. */
  308. function action_pmprefs($memID)
  309. {
  310. global $context, $txt, $scripturl;
  311. require_once(SUBSDIR . '/Profile.subs.php');
  312. loadThemeOptions($memID);
  313. loadCustomFields($memID, 'pmprefs');
  314. $context['sub_template'] = 'edit_options';
  315. $context['page_desc'] = $txt['pm_settings_desc'];
  316. setupProfileContext(
  317. array(
  318. 'pm_prefs',
  319. )
  320. );
  321. }
  322. /**
  323. * Allow the user to pick a theme.
  324. *
  325. * @param int $memID id_member
  326. */
  327. function action_themepick($memID)
  328. {
  329. global $txt, $context, $user_profile, $modSettings, $settings, $user_info, $smcFunc;
  330. require_once(SUBSDIR . '/Profile.subs.php');
  331. loadThemeOptions($memID);
  332. if (allowedTo(array('profile_extra_own', 'profile_extra_any')))
  333. loadCustomFields($memID, 'theme');
  334. $context['sub_template'] = 'edit_options';
  335. $context['page_desc'] = $txt['theme_info'];
  336. setupProfileContext(
  337. array(
  338. 'id_theme', 'smiley_set', 'hr',
  339. 'time_format', 'time_offset', 'hr',
  340. 'theme_settings',
  341. )
  342. );
  343. }
  344. /**
  345. * Changing authentication method?
  346. * Only appropriate for people using OpenID.
  347. *
  348. * @param int $memID id_member
  349. * @param bool $saving = false
  350. */
  351. function action_authentication($memID, $saving = false)
  352. {
  353. global $context, $cur_profile, $txt, $post_errors, $modSettings;
  354. loadLanguage('Login');
  355. // We are saving?
  356. if ($saving)
  357. {
  358. // Moving to password passed authentication?
  359. if ($_POST['authenticate'] == 'passwd')
  360. {
  361. // Didn't enter anything?
  362. if ($_POST['passwrd1'] == '')
  363. $post_errors[] = 'no_password';
  364. // Do the two entries for the password even match?
  365. elseif (!isset($_POST['passwrd2']) || $_POST['passwrd1'] != $_POST['passwrd2'])
  366. $post_errors[] = 'bad_new_password';
  367. // Is it valid?
  368. else
  369. {
  370. require_once(SUBSDIR . '/Auth.subs.php');
  371. $passwordErrors = validatePassword($_POST['passwrd1'], $cur_profile['member_name'], array($cur_profile['real_name'], $cur_profile['email_address']));
  372. // Were there errors?
  373. if ($passwordErrors != null)
  374. $post_errors[] = 'password_' . $passwordErrors;
  375. }
  376. if (empty($post_errors))
  377. {
  378. // Integration?
  379. call_integration_hook('integrate_reset_pass', array($cur_profile['member_name'], $cur_profile['member_name'], $_POST['passwrd1']));
  380. // Go then.
  381. $passwd = sha1(strtolower($cur_profile['member_name']) . un_htmlspecialchars($_POST['passwrd1']));
  382. // Do the important bits.
  383. updateMemberData($memID, array('openid_uri' => '', 'passwd' => $passwd));
  384. if ($context['user']['is_owner'])
  385. {
  386. setLoginCookie(60 * $modSettings['cookieTime'], $memID, sha1(sha1(strtolower($cur_profile['member_name']) . un_htmlspecialchars($_POST['passwrd2'])) . $cur_profile['password_salt']));
  387. redirectexit('action=profile;area=authentication;updated');
  388. }
  389. else
  390. redirectexit('action=profile;u=' . $memID);
  391. }
  392. return true;
  393. }
  394. // Not right yet!
  395. elseif ($_POST['authenticate'] == 'openid' && !empty($_POST['openid_identifier']))
  396. {
  397. require_once(SUBSDIR . '/OpenID.subs.php');
  398. $_POST['openid_identifier'] = openID_canonize($_POST['openid_identifier']);
  399. if (openid_member_exists($_POST['openid_identifier']))
  400. $post_errors[] = 'openid_in_use';
  401. elseif (empty($post_errors))
  402. {
  403. // Authenticate using the new OpenID URI first to make sure they didn't make a mistake.
  404. if ($context['user']['is_owner'])
  405. {
  406. $_SESSION['new_openid_uri'] = $_POST['openid_identifier'];
  407. openID_validate($_POST['openid_identifier'], false, null, 'change_uri');
  408. }
  409. else
  410. updateMemberData($memID, array('openid_uri' => $_POST['openid_identifier']));
  411. }
  412. }
  413. }
  414. // Some stuff.
  415. $context['member']['openid_uri'] = $cur_profile['openid_uri'];
  416. $context['auth_method'] = empty($cur_profile['openid_uri']) ? 'password' : 'openid';
  417. $context['sub_template'] = 'authentication_method';
  418. }
  419. /**
  420. * Display the notifications and settings for changes.
  421. *
  422. * @param int $memID id_member
  423. */
  424. function action_notification($memID)
  425. {
  426. global $txt, $scripturl, $user_profile, $user_info, $context, $modSettings, $smcFunc, $settings;
  427. // Gonna want this for the list.
  428. require_once(SUBSDIR . '/List.subs.php');
  429. // Fine, start with the board list.
  430. $listOptions = array(
  431. 'id' => 'board_notification_list',
  432. 'width' => '100%',
  433. 'no_items_label' => $txt['notifications_boards_none'] . '<br /><br />' . $txt['notifications_boards_howto'],
  434. 'no_items_align' => 'left',
  435. 'base_href' => $scripturl . '?action=profile;u=' . $memID . ';area=notification',
  436. 'default_sort_col' => 'board_name',
  437. 'get_items' => array(
  438. 'function' => 'list_getBoardNotifications',
  439. 'params' => array(
  440. $memID,
  441. ),
  442. ),
  443. 'columns' => array(
  444. 'board_name' => array(
  445. 'header' => array(
  446. 'value' => $txt['notifications_boards'],
  447. 'class' => 'lefttext first_th',
  448. ),
  449. 'data' => array(
  450. 'function' => create_function('$board', '
  451. global $settings, $txt;
  452. $link = $board[\'link\'];
  453. if ($board[\'new\'])
  454. $link .= \' <a href="\' . $board[\'href\'] . \'"><span class="new_posts">' . $txt['new'] . '</span></a>\';
  455. return $link;
  456. '),
  457. ),
  458. 'sort' => array(
  459. 'default' => 'name',
  460. 'reverse' => 'name DESC',
  461. ),
  462. ),
  463. 'delete' => array(
  464. 'header' => array(
  465. 'value' => '<input type="checkbox" class="input_check" onclick="invertAll(this, this.form);" />',
  466. 'style' => 'width: 4%;',
  467. 'class' => 'centercol',
  468. ),
  469. 'data' => array(
  470. 'sprintf' => array(
  471. 'format' => '<input type="checkbox" name="notify_boards[]" value="%1$d" class="input_check" />',
  472. 'params' => array(
  473. 'id' => false,
  474. ),
  475. ),
  476. 'class' => 'centercol',
  477. ),
  478. ),
  479. ),
  480. 'form' => array(
  481. 'href' => $scripturl . '?action=profile;area=notification;save',
  482. 'include_sort' => true,
  483. 'include_start' => true,
  484. 'hidden_fields' => array(
  485. 'u' => $memID,
  486. 'sa' => $context['menu_item_selected'],
  487. $context['session_var'] => $context['session_id'],
  488. ),
  489. 'token' => $context['token_check'],
  490. ),
  491. 'additional_rows' => array(
  492. array(
  493. 'position' => 'bottom_of_list',
  494. 'value' => '<input type="submit" name="edit_notify_boards" value="' . $txt['notifications_update'] . '" class="button_submit" />',
  495. 'align' => 'right',
  496. ),
  497. ),
  498. );
  499. // Create the board notification list.
  500. createList($listOptions);
  501. // Now do the topic notifications.
  502. $listOptions = array(
  503. 'id' => 'topic_notification_list',
  504. 'width' => '100%',
  505. 'items_per_page' => $modSettings['defaultMaxMessages'],
  506. 'no_items_label' => $txt['notifications_topics_none'] . '<br /><br />' . $txt['notifications_topics_howto'],
  507. 'no_items_align' => 'left',
  508. 'base_href' => $scripturl . '?action=profile;u=' . $memID . ';area=notification',
  509. 'default_sort_col' => 'last_post',
  510. 'get_items' => array(
  511. 'function' => 'list_getTopicNotifications',
  512. 'params' => array(
  513. $memID,
  514. ),
  515. ),
  516. 'get_count' => array(
  517. 'function' => 'list_getTopicNotificationCount',
  518. 'params' => array(
  519. $memID,
  520. ),
  521. ),
  522. 'columns' => array(
  523. 'subject' => array(
  524. 'header' => array(
  525. 'value' => $txt['notifications_topics'],
  526. 'class' => 'lefttext first_th',
  527. ),
  528. 'data' => array(
  529. 'function' => create_function('$topic', '
  530. global $settings, $txt;
  531. $link = $topic[\'link\'];
  532. if ($topic[\'new\'])
  533. $link .= \' <a href="\' . $topic[\'new_href\'] . \'"><span class="new_posts">\' . $txt[\'new\'] . \'</span></a>\';
  534. $link .= \'<br /><span class="smalltext"><em>\' . $txt[\'in\'] . \' \' . $topic[\'board_link\'] . \'</em></span>\';
  535. return $link;
  536. '),
  537. ),
  538. 'sort' => array(
  539. 'default' => 'ms.subject',
  540. 'reverse' => 'ms.subject DESC',
  541. ),
  542. ),
  543. 'started_by' => array(
  544. 'header' => array(
  545. 'value' => $txt['started_by'],
  546. 'class' => 'lefttext',
  547. ),
  548. 'data' => array(
  549. 'db' => 'poster_link',
  550. ),
  551. 'sort' => array(
  552. 'default' => 'real_name_col',
  553. 'reverse' => 'real_name_col DESC',
  554. ),
  555. ),
  556. 'last_post' => array(
  557. 'header' => array(
  558. 'value' => $txt['last_post'],
  559. 'class' => 'lefttext',
  560. ),
  561. 'data' => array(
  562. 'sprintf' => array(
  563. 'format' => '<span class="smalltext">%1$s<br />' . $txt['by'] . ' %2$s</span>',
  564. 'params' => array(
  565. 'updated' => false,
  566. 'poster_updated_link' => false,
  567. ),
  568. ),
  569. ),
  570. 'sort' => array(
  571. 'default' => 'ml.id_msg DESC',
  572. 'reverse' => 'ml.id_msg',
  573. ),
  574. ),
  575. 'delete' => array(
  576. 'header' => array(
  577. 'value' => '<input type="checkbox" class="input_check" onclick="invertAll(this, this.form);" />',
  578. 'style' => 'width: 4%;',
  579. 'class' => 'centercol',
  580. ),
  581. 'data' => array(
  582. 'sprintf' => array(
  583. 'format' => '<input type="checkbox" name="notify_topics[]" value="%1$d" class="input_check" />',
  584. 'params' => array(
  585. 'id' => false,
  586. ),
  587. ),
  588. 'class' => 'centercol',
  589. ),
  590. ),
  591. ),
  592. 'form' => array(
  593. 'href' => $scripturl . '?action=profile;area=notification;save',
  594. 'include_sort' => true,
  595. 'include_start' => true,
  596. 'hidden_fields' => array(
  597. 'u' => $memID,
  598. 'sa' => $context['menu_item_selected'],
  599. $context['session_var'] => $context['session_id'],
  600. ),
  601. 'token' => $context['token_check'],
  602. ),
  603. 'additional_rows' => array(
  604. array(
  605. 'position' => 'bottom_of_list',
  606. 'value' => '<input type="submit" name="edit_notify_topics" value="' . $txt['notifications_update'] . '" class="button_submit" />',
  607. 'align' => 'right',
  608. ),
  609. ),
  610. );
  611. // Create the notification list.
  612. createList($listOptions);
  613. // What options are set?
  614. $context['member'] += array(
  615. 'notify_announcements' => $user_profile[$memID]['notify_announcements'],
  616. 'notify_send_body' => $user_profile[$memID]['notify_send_body'],
  617. 'notify_types' => $user_profile[$memID]['notify_types'],
  618. 'notify_regularity' => $user_profile[$memID]['notify_regularity'],
  619. );
  620. loadThemeOptions($memID);
  621. }
  622. /**
  623. * @todo needs a description
  624. *
  625. * @param int $memID id_member
  626. * @return string
  627. */
  628. function list_getTopicNotificationCount($memID)
  629. {
  630. global $smcFunc, $user_info, $context, $modSettings;
  631. $request = $smcFunc['db_query']('', '
  632. SELECT COUNT(*)
  633. FROM {db_prefix}log_notify AS ln' . (!$modSettings['postmod_active'] && $user_info['query_see_board'] === '1=1' ? '' : '
  634. INNER JOIN {db_prefix}topics AS t ON (t.id_topic = ln.id_topic)') . ($user_info['query_see_board'] === '1=1' ? '' : '
  635. INNER JOIN {db_prefix}boards AS b ON (b.id_board = t.id_board)') . '
  636. WHERE ln.id_member = {int:selected_member}' . ($user_info['query_see_board'] === '1=1' ? '' : '
  637. AND {query_see_board}') . ($modSettings['postmod_active'] ? '
  638. AND t.approved = {int:is_approved}' : ''),
  639. array(
  640. 'selected_member' => $memID,
  641. 'is_approved' => 1,
  642. )
  643. );
  644. list ($totalNotifications) = $smcFunc['db_fetch_row']($request);
  645. $smcFunc['db_free_result']($request);
  646. // @todo make this an integer before it gets returned
  647. return $totalNotifications;
  648. }
  649. /**
  650. * @todo Needs a description
  651. *
  652. * @param int $start
  653. * @param int $items_per_page
  654. * @param string $sort
  655. * @param int $memID id_member
  656. * @return array $notification_topics
  657. */
  658. function list_getTopicNotifications($start, $items_per_page, $sort, $memID)
  659. {
  660. global $smcFunc, $txt, $scripturl, $user_info, $context, $modSettings;
  661. // All the topics with notification on...
  662. $request = $smcFunc['db_query']('', '
  663. SELECT
  664. IFNULL(lt.id_msg, IFNULL(lmr.id_msg, -1)) + 1 AS new_from, b.id_board, b.name,
  665. t.id_topic, ms.subject, ms.id_member, IFNULL(mem.real_name, ms.poster_name) AS real_name_col,
  666. ml.id_msg_modified, ml.poster_time, ml.id_member AS id_member_updated,
  667. IFNULL(mem2.real_name, ml.poster_name) AS last_real_name
  668. FROM {db_prefix}log_notify AS ln
  669. INNER JOIN {db_prefix}topics AS t ON (t.id_topic = ln.id_topic' . ($modSettings['postmod_active'] ? ' AND t.approved = {int:is_approved}' : '') . ')
  670. INNER JOIN {db_prefix}boards AS b ON (b.id_board = t.id_board AND {query_see_board})
  671. INNER JOIN {db_prefix}messages AS ms ON (ms.id_msg = t.id_first_msg)
  672. INNER JOIN {db_prefix}messages AS ml ON (ml.id_msg = t.id_last_msg)
  673. LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = ms.id_member)
  674. LEFT JOIN {db_prefix}members AS mem2 ON (mem2.id_member = ml.id_member)
  675. LEFT JOIN {db_prefix}log_topics AS lt ON (lt.id_topic = t.id_topic AND lt.id_member = {int:current_member})
  676. LEFT JOIN {db_prefix}log_mark_read AS lmr ON (lmr.id_board = b.id_board AND lmr.id_member = {int:current_member})
  677. WHERE ln.id_member = {int:selected_member}
  678. ORDER BY {raw:sort}
  679. LIMIT {int:offset}, {int:items_per_page}',
  680. array(
  681. 'current_member' => $user_info['id'],
  682. 'is_approved' => 1,
  683. 'selected_member' => $memID,
  684. 'sort' => $sort,
  685. 'offset' => $start,
  686. 'items_per_page' => $items_per_page,
  687. )
  688. );
  689. $notification_topics = array();
  690. while ($row = $smcFunc['db_fetch_assoc']($request))
  691. {
  692. censorText($row['subject']);
  693. $notification_topics[] = array(
  694. 'id' => $row['id_topic'],
  695. 'poster_link' => empty($row['id_member']) ? $row['real_name_col'] : '<a href="' . $scripturl . '?action=profile;u=' . $row['id_member'] . '">' . $row['real_name_col'] . '</a>',
  696. 'poster_updated_link' => empty($row['id_member_updated']) ? $row['last_real_name'] : '<a href="' . $scripturl . '?action=profile;u=' . $row['id_member_updated'] . '">' . $row['last_real_name'] . '</a>',
  697. 'subject' => $row['subject'],
  698. 'href' => $scripturl . '?topic=' . $row['id_topic'] . '.0',
  699. 'link' => '<a href="' . $scripturl . '?topic=' . $row['id_topic'] . '.0">' . $row['subject'] . '</a>',
  700. 'new' => $row['new_from'] <= $row['id_msg_modified'],
  701. 'new_from' => $row['new_from'],
  702. 'updated' => timeformat($row['poster_time']),
  703. 'new_href' => $scripturl . '?topic=' . $row['id_topic'] . '.msg' . $row['new_from'] . '#new',
  704. 'new_link' => '<a href="' . $scripturl . '?topic=' . $row['id_topic'] . '.msg' . $row['new_from'] . '#new">' . $row['subject'] . '</a>',
  705. 'board_link' => '<a href="' . $scripturl . '?board=' . $row['id_board'] . '.0">' . $row['name'] . '</a>',
  706. );
  707. }
  708. $smcFunc['db_free_result']($request);
  709. return $notification_topics;
  710. }
  711. /**
  712. * @todo needs a description
  713. *
  714. * @param int $start
  715. * @param int $items_per_page
  716. * @param string $sort
  717. * @param int $memID id_member
  718. * @return array
  719. */
  720. function list_getBoardNotifications($start, $items_per_page, $sort, $memID)
  721. {
  722. global $smcFunc, $txt, $scripturl, $user_info;
  723. $request = $smcFunc['db_query']('', '
  724. SELECT b.id_board, b.name, IFNULL(lb.id_msg, 0) AS board_read, b.id_msg_updated
  725. FROM {db_prefix}log_notify AS ln
  726. INNER JOIN {db_prefix}boards AS b ON (b.id_board = ln.id_board)
  727. LEFT JOIN {db_prefix}log_boards AS lb ON (lb.id_board = b.id_board AND lb.id_member = {int:current_member})
  728. WHERE ln.id_member = {int:selected_member}
  729. AND {query_see_board}
  730. ORDER BY ' . $sort,
  731. array(
  732. 'current_member' => $user_info['id'],
  733. 'selected_member' => $memID,
  734. )
  735. );
  736. $notification_boards = array();
  737. while ($row = $smcFunc['db_fetch_assoc']($request))
  738. $notification_boards[] = array(
  739. 'id' => $row['id_board'],
  740. 'name' => $row['name'],
  741. 'href' => $scripturl . '?board=' . $row['id_board'] . '.0',
  742. 'link' => '<a href="' . $scripturl . '?board=' . $row['id_board'] . '.0">' . $row['name'] . '</a>',
  743. 'new' => $row['board_read'] < $row['id_msg_updated']
  744. );
  745. $smcFunc['db_free_result']($request);
  746. return $notification_boards;
  747. }
  748. /**
  749. * Load the options for an user.
  750. *
  751. * @param int $memID id_member
  752. */
  753. function loadThemeOptions($memID)
  754. {
  755. global $context, $options, $cur_profile, $smcFunc;
  756. if (isset($_POST['default_options']))
  757. $_POST['options'] = isset($_POST['options']) ? $_POST['options'] + $_POST['default_options'] : $_POST['default_options'];
  758. if ($context['user']['is_owner'])
  759. {
  760. $context['member']['options'] = $options;
  761. if (isset($_POST['options']) && is_array($_POST['options']))
  762. foreach ($_POST['options'] as $k => $v)
  763. $context['member']['options'][$k] = $v;
  764. }
  765. else
  766. {
  767. $request = $smcFunc['db_query']('', '
  768. SELECT id_member, variable, value
  769. FROM {db_prefix}themes
  770. WHERE id_theme IN (1, {int:member_theme})
  771. AND id_member IN (-1, {int:selected_member})',
  772. array(
  773. 'member_theme' => (int) $cur_profile['id_theme'],
  774. 'selected_member' => $memID,
  775. )
  776. );
  777. $temp = array();
  778. while ($row = $smcFunc['db_fetch_assoc']($request))
  779. {
  780. if ($row['id_member'] == -1)
  781. {
  782. $temp[$row['variable']] = $row['value'];
  783. continue;
  784. }
  785. if (isset($_POST['options'][$row['variable']]))
  786. $row['value'] = $_POST['options'][$row['variable']];
  787. $context['member']['options'][$row['variable']] = $row['value'];
  788. }
  789. $smcFunc['db_free_result']($request);
  790. // Load up the default theme options for any missing.
  791. foreach ($temp as $k => $v)
  792. {
  793. if (!isset($context['member']['options'][$k]))
  794. $context['member']['options'][$k] = $v;
  795. }
  796. }
  797. }
  798. /**
  799. * Allows the user to see the list of their ignored boards.
  800. * (and un-ignore them)
  801. *
  802. * @param int $memID id_member
  803. */
  804. function action_ignoreboards($memID)
  805. {
  806. global $txt, $user_info, $context, $modSettings, $smcFunc, $cur_profile;
  807. // Have the admins enabled this option?
  808. if (empty($modSettings['allow_ignore_boards']))
  809. fatal_lang_error('ignoreboards_disallowed', 'user');
  810. // Find all the boards this user is allowed to see.
  811. $request = $smcFunc['db_query']('order_by_board_order', '
  812. SELECT b.id_cat, c.name AS cat_name, b.id_board, b.name, b.child_level,
  813. '. (!empty($cur_profile['ignore_boards']) ? 'b.id_board IN ({array_int:ignore_boards})' : '0') . ' AS is_ignored
  814. FROM {db_prefix}boards AS b
  815. LEFT JOIN {db_prefix}categories AS c ON (c.id_cat = b.id_cat)
  816. WHERE {query_see_board}
  817. AND redirect = {string:empty_string}',
  818. array(
  819. 'ignore_boards' => !empty($cur_profile['ignore_boards']) ? explode(',', $cur_profile['ignore_boards']) : array(),
  820. 'empty_string' => '',
  821. )
  822. );
  823. $context['num_boards'] = $smcFunc['db_num_rows']($request);
  824. $context['categories'] = array();
  825. while ($row = $smcFunc['db_fetch_assoc']($request))
  826. {
  827. // This category hasn't been set up yet..
  828. if (!isset($context['categories'][$row['id_cat']]))
  829. $context['categories'][$row['id_cat']] = array(
  830. 'id' => $row['id_cat'],
  831. 'name' => $row['cat_name'],
  832. 'boards' => array()
  833. );
  834. // Set this board up, and let the template know when it's a child. (indent them..)
  835. $context['categories'][$row['id_cat']]['boards'][$row['id_board']] = array(
  836. 'id' => $row['id_board'],
  837. 'name' => $row['name'],
  838. 'child_level' => $row['child_level'],
  839. 'selected' => $row['is_ignored'],
  840. );
  841. }
  842. $smcFunc['db_free_result']($request);
  843. // Now, let's sort the list of categories into the boards for templates that like that.
  844. $temp_boards = array();
  845. foreach ($context['categories'] as $category)
  846. {
  847. // Include a list of boards per category for easy toggling.
  848. $context['categories'][$category['id']]['child_ids'] = array_keys($category['boards']);
  849. $temp_boards[] = array(
  850. 'name' => $category['name'],
  851. 'child_ids' => array_keys($category['boards'])
  852. );
  853. $temp_boards = array_merge($temp_boards, array_values($category['boards']));
  854. }
  855. $max_boards = ceil(count($temp_boards) / 2);
  856. if ($max_boards == 1)
  857. $max_boards = 2;
  858. // Now, alternate them so they can be shown left and right ;).
  859. $context['board_columns'] = array();
  860. for ($i = 0; $i < $max_boards; $i++)
  861. {
  862. $context['board_columns'][] = $temp_boards[$i];
  863. if (isset($temp_boards[$i + $max_boards]))
  864. $context['board_columns'][] = $temp_boards[$i + $max_boards];
  865. else
  866. $context['board_columns'][] = array();
  867. }
  868. loadThemeOptions($memID);
  869. }
  870. /**
  871. * Function to allow the user to choose group membership etc...
  872. *
  873. * @param int $memID id_member
  874. */
  875. function action_groupMembership($memID)
  876. {
  877. global $txt, $scripturl, $user_profile, $user_info, $context, $modSettings, $smcFunc;
  878. $curMember = $user_profile[$memID];
  879. $context['primary_group'] = $curMember['id_group'];
  880. // Can they manage groups?
  881. $context['can_manage_membergroups'] = allowedTo('manage_membergroups');
  882. $context['can_manage_protected'] = allowedTo('admin_forum');
  883. $context['can_edit_primary'] = $context['can_manage_protected'];
  884. $context['update_message'] = isset($_GET['msg']) && isset($txt['group_membership_msg_' . $_GET['msg']]) ? $txt['group_membership_msg_' . $_GET['msg']] : '';
  885. // Get all the groups this user is a member of.
  886. $groups = explode(',', $curMember['additional_groups']);
  887. $groups[] = $curMember['id_group'];
  888. // Ensure the query doesn't croak!
  889. if (empty($groups))
  890. $groups = array(0);
  891. // Just to be sure...
  892. foreach ($groups as $k => $v)
  893. $groups[$k] = (int) $v;
  894. // Get all the membergroups they can join.
  895. $request = $smcFunc['db_query']('', '
  896. SELECT mg.id_group, mg.group_name, mg.description, mg.group_type, mg.online_color, mg.hidden,
  897. IFNULL(lgr.id_member, 0) AS pending
  898. FROM {db_prefix}membergroups AS mg
  899. LEFT JOIN {db_prefix}log_group_requests AS lgr ON (lgr.id_member = {int:selected_member} AND lgr.id_group = mg.id_group)
  900. WHERE (mg.id_group IN ({array_int:group_list})
  901. OR mg.group_type > {int:nonjoin_group_id})
  902. AND mg.min_posts = {int:min_posts}
  903. AND mg.id_group != {int:moderator_group}
  904. ORDER BY group_name',
  905. array(
  906. 'group_list' => $groups,
  907. 'selected_member' => $memID,
  908. 'nonjoin_group_id' => 1,
  909. 'min_posts' => -1,
  910. 'moderator_group' => 3,
  911. )
  912. );
  913. // This beast will be our group holder.
  914. $context['groups'] = array(
  915. 'member' => array(),
  916. 'available' => array()
  917. );
  918. while ($row = $smcFunc['db_fetch_assoc']($request))
  919. {
  920. // Can they edit their primary group?
  921. if (($row['id_group'] == $context['primary_group'] && $row['group_type'] > 1) || ($row['hidden'] != 2 && $context['primary_group'] == 0 && in_array($row['id_group'], $groups)))
  922. $context['can_edit_primary'] = true;
  923. // If they can't manage (protected) groups, and it's not publically joinable or already assigned, they can't see it.
  924. if (((!$context['can_manage_protected'] && $row['group_type'] == 1) || (!$context['can_manage_membergroups'] && $row['group_type'] == 0)) && $row['id_group'] != $context['primary_group'])
  925. continue;
  926. $context['groups'][in_array($row['id_group'], $groups) ? 'member' : 'available'][$row['id_group']] = array(
  927. 'id' => $row['id_group'],
  928. 'name' => $row['group_name'],
  929. 'desc' => $row['description'],
  930. 'color' => $row['online_color'],
  931. 'type' => $row['group_type'],
  932. 'pending' => $row['pending'],
  933. 'is_primary' => $row['id_group'] == $context['primary_group'],
  934. 'can_be_primary' => $row['hidden'] != 2,
  935. // Anything more than this needs to be done through account settings for security.
  936. 'can_leave' => $row['id_group'] != 1 && $row['group_type'] > 1 ? true : false,
  937. );
  938. }
  939. $smcFunc['db_free_result']($request);
  940. // Add registered members on the end.
  941. $context['groups']['member'][0] = array(
  942. 'id' => 0,
  943. 'name' => $txt['regular_members'],
  944. 'desc' => $txt['regular_members_desc'],
  945. 'type' => 0,
  946. 'is_primary' => $context['primary_group'] == 0 ? true : false,
  947. 'can_be_primary' => true,
  948. 'can_leave' => 0,
  949. );
  950. // No changing primary one unless you have enough groups!
  951. if (count($context['groups']['member']) < 2)
  952. $context['can_edit_primary'] = false;
  953. // In the special case that someone is requesting membership of a group, setup some special context vars.
  954. if (isset($_REQUEST['request']) && isset($context['groups']['available'][(int) $_REQUEST['request']]) && $context['groups']['available'][(int) $_REQUEST['request']]['type'] == 2)
  955. $context['group_request'] = $context['groups']['available'][(int) $_REQUEST['request']];
  956. }
  957. /**
  958. * This function actually makes all the group changes
  959. *
  960. * @param array $profile_vars
  961. * @param array $post_errors
  962. * @param int $memID id_member
  963. * @return mixed
  964. */
  965. function action_groupMembership2($profile_vars, $post_errors, $memID)
  966. {
  967. global $user_info, $context, $user_profile, $modSettings, $txt, $smcFunc, $scripturl, $language;
  968. // Let's be extra cautious...
  969. if (!$context['user']['is_owner'] || empty($modSettings['show_group_membership']))
  970. isAllowedTo('manage_membergroups');
  971. if (!isset($_REQUEST['gid']) && !isset($_POST['primary']))
  972. fatal_lang_error('no_access', false);
  973. checkSession(isset($_GET['gid']) ? 'get' : 'post');
  974. require_once(SUBSDIR . '/Membergroups.subs.php');
  975. $old_profile = &$user_profile[$memID];
  976. $context['can_manage_membergroups'] = allowedTo('manage_membergroups');
  977. $context['can_manage_protected'] = allowedTo('admin_forum');
  978. // By default the new primary is the old one.
  979. $newPrimary = $old_profile['id_group'];
  980. $addGroups = array_flip(explode(',', $old_profile['additional_groups']));
  981. $canChangePrimary = $old_profile['id_group'] == 0 ? 1 : 0;
  982. $changeType = isset($_POST['primary']) ? 'primary' : (isset($_POST['req']) ? 'request' : 'free');
  983. // One way or another, we have a target group in mind...
  984. $group_id = isset($_REQUEST['gid']) ? (int) $_REQUEST['gid'] : (int) $_POST['primary'];
  985. $foundTarget = $changeType == 'primary' && $group_id == 0 ? true : false;
  986. // Sanity check!!
  987. if ($group_id == 1)
  988. isAllowedTo('admin_forum');
  989. // Protected groups too!
  990. else
  991. {
  992. $is_protected = membergroupsById($group_id);
  993. if ($is_protected['group_type'] == 1)
  994. isAllowedTo('admin_forum');
  995. }
  996. // What ever we are doing, we need to determine if changing primary is possible!
  997. $groups_details = membergroupsById(array($group_id, $old_profile['id_group']), 0, true);
  998. foreach ($groups_details as $key => $row)
  999. {
  1000. // Is this the new group?
  1001. if ($row['id_group'] == $group_id)
  1002. {
  1003. $foundTarget = true;
  1004. $group_name = $row['group_name'];
  1005. // Does the group type match what we're doing - are we trying to request a non-requestable group?
  1006. if ($changeType == 'request' && $row['group_type'] != 2)
  1007. fatal_lang_error('no_access', false);
  1008. // What about leaving a requestable group we are not a member of?
  1009. elseif ($changeType == 'free' && $row['group_type'] == 2 && $old_profile['id_group'] != $row['id_group'] && !isset($addGroups[$row['id_group']]))
  1010. fatal_lang_error('no_access', false);
  1011. elseif ($changeType == 'free' && $row['group_type'] != 3 && $row['group_type'] != 2)
  1012. fatal_lang_error('no_access', false);
  1013. // We can't change the primary group if this is hidden!
  1014. if ($row['hidden'] == 2)
  1015. $canChangePrimary = false;
  1016. }
  1017. // If this is their old primary, can we change it?
  1018. if ($row['id_group'] == $old_profile['id_group'] && ($row['group_type'] > 1 || $context['can_manage_membergroups']) && $canChangePrimary !== false)
  1019. $canChangePrimary = 1;
  1020. // If we are not doing a force primary move, don't do it automatically if current primary is not 0.
  1021. if ($changeType != 'primary' && $old_profile['id_group'] != 0)
  1022. $canChangePrimary = false;
  1023. // If this is the one we are acting on, can we even act?
  1024. if ((!$context['can_manage_protected'] && $row['group_type'] == 1) || (!$context['can_manage_membergroups'] && $row['group_type'] == 0))
  1025. $canChangePrimary = false;
  1026. }
  1027. // Didn't find the target?
  1028. if (!$foundTarget)
  1029. fatal_lang_error('no_access', false);
  1030. // Final security check, don't allow users to promote themselves to admin.
  1031. if ($context['can_manage_membergroups'] && !allowedTo('admin_forum'))
  1032. {
  1033. $request = $smcFunc['db_query']('', '
  1034. SELECT COUNT(permission)
  1035. FROM {db_prefix}permissions
  1036. WHERE id_group = {int:selected_group}
  1037. AND permission = {string:admin_forum}
  1038. AND add_deny = {int:not_denied}',
  1039. array(
  1040. 'selected_group' => $group_id,
  1041. 'not_denied' => 1,
  1042. 'admin_forum' => 'admin_forum',
  1043. )
  1044. );
  1045. list ($disallow) = $smcFunc['db_fetch_row']($request);
  1046. $smcFunc['db_free_result']($request);
  1047. if ($disallow)
  1048. isAllowedTo('admin_forum');
  1049. }
  1050. // If we're requesting, add the note then return.
  1051. if ($changeType == 'request')
  1052. {
  1053. $request = $smcFunc['db_query']('', '
  1054. SELECT id_member
  1055. FROM {db_prefix}log_group_requests
  1056. WHERE id_member = {int:selected_member}
  1057. AND id_group = {int:selected_group}',
  1058. array(
  1059. 'selected_member' => $memID,
  1060. 'selected_group' => $group_id,
  1061. )
  1062. );
  1063. if ($smcFunc['db_num_rows']($request) != 0)
  1064. fatal_lang_error('profile_error_already_requested_group');
  1065. $smcFunc['db_free_result']($request);
  1066. // Log the request.
  1067. $smcFunc['db_insert']('',
  1068. '{db_prefix}log_group_requests',
  1069. array(
  1070. 'id_member' => 'int', 'id_group' => 'int', 'time_applied' => 'int', 'reason' => 'string-65534',
  1071. ),
  1072. array(
  1073. $memID, $group_id, time(), $_POST['reason'],
  1074. ),
  1075. array('id_request')
  1076. );
  1077. // Send an email to all group moderators etc.
  1078. require_once(SUBSDIR . '/Mail.subs.php');
  1079. // Do we have any group moderators?
  1080. $request = $smcFunc['db_query']('', '
  1081. SELECT id_member
  1082. FROM {db_prefix}group_moderators
  1083. WHERE id_group = {int:selected_group}',
  1084. array(
  1085. 'selected_group' => $group_id,
  1086. )
  1087. );
  1088. $moderators = array();
  1089. while ($row = $smcFunc['db_fetch_assoc']($request))
  1090. $moderators[] = $row['id_member'];
  1091. $smcFunc['db_free_result']($request);
  1092. // Otherwise this is the backup!
  1093. if (empty($moderators))
  1094. {
  1095. require_once(SUBSDIR . '/Members.subs.php');
  1096. $moderators = membersAllowedTo('manage_membergroups');
  1097. }
  1098. if (!empty($moderators))
  1099. {
  1100. $request = $smcFunc['db_query']('', '
  1101. SELECT id_member, email_address, lngfile, member_name, mod_prefs
  1102. FROM {db_prefix}members
  1103. WHERE id_member IN ({array_int:moderator_list})
  1104. AND notify_types != {int:no_notifications}
  1105. ORDER BY lngfile',
  1106. array(
  1107. 'moderator_list' => $moderators,
  1108. 'no_notifications' => 4,
  1109. )
  1110. );
  1111. while ($row = $smcFunc['db_fetch_assoc']($request))
  1112. {
  1113. // Check whether they are interested.
  1114. if (!empty($row['mod_prefs']))
  1115. {
  1116. list(,, $pref_binary) = explode('|', $row['mod_prefs']);
  1117. if (!($pref_binary & 4))
  1118. continue;
  1119. }
  1120. $replacements = array(
  1121. 'RECPNAME' => $row['member_name'],
  1122. 'APPYNAME' => $old_profile['member_name'],
  1123. 'GROUPNAME' => $group_name,
  1124. 'REASON' => $_POST['reason'],
  1125. 'MODLINK' => $scripturl . '?action=moderate;area=groups;sa=requests',
  1126. );
  1127. $emaildata = loadEmailTemplate('request_membership', $replacements, empty($row['lngfile']) || empty($modSettings['userLanguage']) ? $language : $row['lngfile']);
  1128. sendmail($row['email_address'], $emaildata['subject'], $emaildata['body'], null, null, false, 2);
  1129. }
  1130. $smcFunc['db_free_result']($request);
  1131. }
  1132. return $changeType;
  1133. }
  1134. // Otherwise we are leaving/joining a group.
  1135. elseif ($changeType == 'free')
  1136. {
  1137. // Are we leaving?
  1138. if ($old_profile['id_group'] == $group_id || isset($addGroups[$group_id]))
  1139. {
  1140. if ($old_profile['id_group'] == $group_id)
  1141. $newPrimary = 0;
  1142. else
  1143. unset($addGroups[$group_id]);
  1144. }
  1145. // ... if not, must be joining.
  1146. else
  1147. {
  1148. // Can we change the primary, and do we want to?
  1149. if ($canChangePrimary)
  1150. {
  1151. if ($old_profile['id_group'] != 0)
  1152. $addGroups[$old_profile['id_group']] = -1;
  1153. $newPrimary = $group_id;
  1154. }
  1155. // Otherwise it's an additional group...
  1156. else
  1157. $addGroups[$group_id] = -1;
  1158. }
  1159. }
  1160. // Finally, we must be setting the primary.
  1161. elseif ($canChangePrimary)
  1162. {
  1163. if ($old_profile['id_group'] != 0)
  1164. $addGroups[$old_profile['id_group']] = -1;
  1165. if (isset($addGroups[$group_id]))
  1166. unset($addGroups[$group_id]);
  1167. $newPrimary = $group_id;
  1168. }
  1169. // Finally, we can make the changes!
  1170. foreach ($addGroups as $id => $dummy)
  1171. if (empty($id))
  1172. unset($addGroups[$id]);
  1173. $addGroups = implode(',', array_flip($addGroups));
  1174. // Ensure that we don't cache permissions if the group is changing.
  1175. if ($context['user']['is_owner'])
  1176. $_SESSION['mc']['time'] = 0;
  1177. else
  1178. updateSettings(array('settings_updated' => time()));
  1179. updateMemberData($memID, array('id_group' => $newPrimary, 'additional_groups' => $addGroups));
  1180. return $changeType;
  1181. }