Advertisement
Guest User

Untitled

a guest
Sep 15th, 2014
342
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 17.25 KB | None | 0 0
  1. <?php
  2. /**
  3. * Main mentions file for @mentions mod for SMF
  4. *
  5. * @author Shitiz Garg <mail@dragooon.net>
  6. * @copyright 2014 Shitiz Garg
  7. * @license Simplified BSD (2-Clause) License
  8. */
  9.  
  10. /**
  11. * Callback for integrate_bbc_codes
  12. *
  13. * @param array &$bbc_tags
  14. * @return void
  15. */
  16. function mentions_bbc(array &$bbc_tags)
  17. {
  18. global $scripturl;
  19.  
  20. $bbc_tags[] = array(
  21. 'tag' => 'member',
  22. 'type' => 'unparsed_equals',
  23. 'before' => '<a href="' . $scripturl . '?action=profile;u=$1" class="mention">@',
  24. 'after' => '</a>',
  25. );
  26. }
  27.  
  28. /**
  29. * Callback for integrate_emnu_buttons
  30. *
  31. * @param array &$menu_buttons
  32. * @return void
  33. */
  34. function mentions_menu(array &$menu_buttons)
  35. {
  36. global $txt, $scripturl, $smcFunc, $user_info, $user_settings;
  37.  
  38. loadLanguage('Mentions');
  39.  
  40. $menu_buttons['profile']['sub_buttons']['mentions'] = array(
  41. 'title' => $txt['mentions'] . (!empty($user_settings['unread_mentions']) ? ' [' . $user_settings['unread_mentions'] . ']' : ''),
  42. 'href' => $scripturl . '?action=profile;area=mentions',
  43. 'show' => true,
  44. );
  45. $menu_buttons['profile']['title'] .= (!empty($user_settings['unread_mentions']) ? ' [' . $user_settings['unread_mentions'] . ']' : '');
  46. }
  47.  
  48. /**
  49. * Hook callback for integrate_profile_areas
  50. *
  51. * @param array $profile_areas
  52. * @return void
  53. */
  54. function mentions_profile_areas(array &$profile_areas)
  55. {
  56. global $txt;
  57.  
  58. loadLanguage('Mentions');
  59.  
  60. $profile_areas['info']['areas']['mentions'] = array(
  61. 'label' => $txt['mentions'],
  62. 'enabled' => true,
  63. 'file' => 'Mentions.php',
  64. 'function' => 'Mentions_Profile',
  65. 'permission' => array(
  66. 'own' => 'profile_view_own',
  67. 'any' => 'profile_identity_any',
  68. ),
  69. );
  70. }
  71.  
  72. /**
  73. * Hook callback for integrate_load_permissions
  74. *
  75. * @param array &$permissionGroups
  76. * @param array &$permissionList
  77. * @param array &$leftPermissionGroups
  78. * @param array &$hiddenPermissions
  79. * @param array &$relabelPermissions
  80. * @return void
  81. */
  82. function mentions_permissions(array &$permissionGroups, array &$permissionList, array &$leftPermissionGroups, array &$hiddenPermissions, array &$relabelPermissions)
  83. {
  84. loadLanguage('Mentions');
  85.  
  86. $permissionList['membergroup']['mention_member'] = array(false, 'general', 'view_basic_info');
  87. }
  88.  
  89. /**
  90. * Parses a post, actually looks for mentions and stores then in $msgOptions
  91. * We can't actually store them here if we don't have the ID of the post
  92. *
  93. * Names are tagged by "@<username>" format in post, but they can contain
  94. * any type of character up to 60 characters length. So we extract, starting from @
  95. * up to 60 characters in length (or if we encounter a line break) and make
  96. * several combination of strings after splitting it by anything that's not a word and join
  97. * by having the first word, first and second word, first, second and third word and so on and
  98. * search every name.
  99. *
  100. * One potential problem with this is something like "@Admin Space" can match
  101. * "Admin Space" as well as "Admin", so we sort by length in descending order.
  102. * One disadvantage of this is that we can only match by one column, hence I've chosen
  103. * real_name since it's the most obvious.
  104. *
  105. * If there's an @ symbol within the name, it is counted in the ongoing string and a new
  106. * combination string is started from it as well in order to account for all the possibilities.
  107. * This makes the @ symbol to not be required to be escaped
  108. *
  109. * @param array &$msgOptions
  110. * @param array &$topicOptions
  111. * @param array &$posterOptions
  112. * @return void
  113. */
  114. function mentions_process_post(&$msgOptions, &$topicOptions, &$posterOptions)
  115. {
  116. global $smcFunc, $user_info;
  117.  
  118. // Undo some of the preparse code action
  119. $body = htmlspecialchars_decode(preg_replace('~<br\s*/?\>~', "\n", str_replace('&nbsp;', ' ', $msgOptions['body'])), ENT_QUOTES);
  120.  
  121. $matches = array();
  122. $string = str_split($body);
  123. $depth = 0;
  124. foreach ($string as $char)
  125. {
  126. if ($char == '@')
  127. {
  128. $depth++;
  129. $matches[] = array();
  130. }
  131. elseif ($char == "\n")
  132. $depth = 0;
  133.  
  134. for ($i = $depth; $i > 0; $i--)
  135. {
  136. if (count($matches[count($matches) - $i]) > 60)
  137. {
  138. $depth--;
  139. break;
  140. }
  141. $matches[count($matches) - $i][] = $char;
  142. }
  143. }
  144.  
  145. foreach ($matches as $k => $match)
  146. $matches[$k] = substr(implode('', $match), 1);
  147.  
  148. // Names can have spaces, or they can't...we try to match every possible
  149. if (empty($matches) || !allowedTo('mention_member'))
  150. return;
  151.  
  152. // Names can have spaces, other breaks, or they can't...we try to match every possible
  153. // combination.
  154. $names = array();
  155. foreach ($matches as $match)
  156. {
  157. $match = preg_split('/([^\w])/', $match, -1, PREG_SPLIT_DELIM_CAPTURE);
  158.  
  159. for ($i = 1; $i <= count($match); $i++)
  160. $names[] = implode('', array_slice($match, 0, $i));
  161. }
  162.  
  163. $names = array_unique(array_map('trim', $names));
  164.  
  165. // Get the membergroups this message can be seen by
  166. $request = $smcFunc['db_query']('', '
  167. SELECT b.member_groups
  168. FROM {db_prefix}boards AS b
  169. WHERE id_board = {int:board}',
  170. array(
  171. 'board' => $topicOptions['board'],
  172. )
  173. );
  174. list ($member_groups) = $smcFunc['db_fetch_row']($request);
  175. $smcFunc['db_free_result']($request);
  176. $member_groups = explode(',', $member_groups);
  177. foreach ($member_groups as $k => $group)
  178. // Dunno why
  179. if (strlen($group) == 0)
  180. unset($member_groups[$k]);
  181.  
  182. // Attempt to fetch all the valid usernames along with their required metadata
  183. $request = $smcFunc['db_query']('', '
  184. SELECT id_member, real_name, email_mentions, email_address, unread_mentions, id_group, id_post_group, additional_groups
  185. FROM {db_prefix}members
  186. WHERE real_name IN ({array_string:names})
  187. ORDER BY LENGTH(real_name) DESC
  188. LIMIT {int:count}',
  189. array(
  190. 'names' => $names,
  191. 'count' => count($names),
  192. )
  193. );
  194. $members = array();
  195. while ($row = $smcFunc['db_fetch_assoc']($request))
  196. $members[$row['id_member']] = array(
  197. 'id' => $row['id_member'],
  198. 'real_name' => $row['real_name'],
  199. 'email_mentions' => $row['email_mentions'],
  200. 'email_address' => $row['email_address'],
  201. 'unread_mentions' => $row['unread_mentions'],
  202. 'groups' => array_unique(array_merge(array($row['id_group'], $row['id_post_group']), explode(',', $row['additional_groups']))),
  203. );
  204. $smcFunc['db_free_result']($request);
  205.  
  206. if (empty($members))
  207. return;
  208.  
  209. // Replace all the tags with BBCode ([member=<id>]<username>[/member])
  210. $msgOptions['mentions'] = array();
  211. foreach ($members as $member)
  212. {
  213. if (stripos($msgOptions['body'], '@' . $member['real_name']) === false
  214. || (!in_array(1, $member['groups']) && count(array_intersect($member['groups'], $member_groups)) == 0))
  215. continue;
  216.  
  217. $msgOptions['body'] = str_ireplace('@' . $member['real_name'], '[member=' . $member['id'] . ']' . $member['real_name'] . '[/member]', $msgOptions['body']);
  218.  
  219. // Why would an idiot mention themselves?
  220. if ($user_info['id'] == $member['id'])
  221. continue;
  222.  
  223. $msgOptions['mentions'][] = $member;
  224. }
  225. }
  226.  
  227. /**
  228. * Takes mention_process_post's arrays and calls mention_store
  229. *
  230. * @param array $mentions
  231. * @param int $id_post
  232. * @param string $subject
  233. * @param bool $approved
  234. * @return void
  235. */
  236. function mentions_process_store(array $mentions, $id_post, $subject, $approved = true)
  237. {
  238. global $smcFunc, $txt, $user_info, $scripturl;
  239.  
  240. foreach ($mentions as $mention)
  241. {
  242. // Store this quickly
  243. $smcFunc['db_insert']('replace',
  244. '{db_prefix}log_mentions',
  245. array('id_post' => 'int', 'id_member' => 'int', 'id_mentioned' => 'int', 'time' => 'int'),
  246. array($id_post, $user_info['id'], $mention['id'], time()),
  247. array('id_post', 'id_member', 'id_mentioned')
  248. );
  249.  
  250. if (!empty($mention['email_mentions']) && $approved)
  251. {
  252. $replacements = array(
  253. 'POSTNAME' => $subject,
  254. 'MENTIONNAME' => $mention['real_name'],
  255. 'MEMBERNAME' => $user_info['name'],
  256. 'POSTLINK' => $scripturl . '?msg=' . $id_post,
  257. );
  258.  
  259. loadLanguage('Mentions');
  260.  
  261. $subject = str_replace(array_keys($replacements), array_values($replacements), $txt['mentions_subject']);
  262. $body = str_replace(array_keys($replacements), array_values($replacements), $txt['mentions_body']);
  263. sendmail($mention['email_address'], $subject, $body);
  264. }
  265.  
  266. if ($approved)
  267. updateMemberData($mention['id'], array('unread_mentions' => $mention['unread_mentions'] + 1));
  268. }
  269. }
  270.  
  271. /**
  272. * Handles approved post's mentions, mostly handles notifications
  273. *
  274. * @param array $msgs
  275. * @return void
  276. */
  277. function mentions_process_approved(array $msgs)
  278. {
  279. global $smcFunc, $txt, $scripturl, $txt;
  280.  
  281. loadLanguage('Mentions');
  282.  
  283. // Grab the appropriate mentions
  284. $request = $smcFunc['db_query']('', '
  285. SELECT msg.id_msg, msg.subject, mem.real_name, ment.real_name AS mentioned_name,
  286. ment.email_mentions, ment.email_address, ment.unread_mentions, ment.id_member
  287. FROM {db_prefix}log_mentions AS lm
  288. INNER JOIN {db_prefix}messages AS msg ON (msg.id_msg = lm.id_post)
  289. INNER JOIN {db_prefix}members AS mem ON (lm.id_member = mem.id_member)
  290. INNER JOIN {db_prefix}members AS ment ON (lm.id_mentioned = ment.id_member)
  291. WHERE lm.id_post IN ({array_int:messages})',
  292. array(
  293. 'messages' => $msgs,
  294. )
  295. );
  296. while ($row = $smcFunc['db_fetch_assoc']($request))
  297. {
  298. if (!empty($row['email_mentions']))
  299. {
  300. $replacements = array(
  301. 'POSTNAME' => $row['subject'],
  302. 'MENTIONNAME' => $row['mentioned_name'],
  303. 'MEMBERNAME' => $row['real_name'],
  304. 'POSTLINK' => $scripturl . '?msg=' . $row['id_msg'],
  305. );
  306.  
  307. $subject = str_replace(array_keys($replacements), array_values($replacements), $txt['mentions_subject']);
  308. $body = str_replace(array_keys($replacements), array_values($replacements), $txt['mentions_body']);
  309. sendmail($row['email_address'], $subject, $body);
  310. }
  311.  
  312. updateMemberData($row['id_member'], array('unread_mentions' => $row['unread_mentions'] + 1));
  313. }
  314.  
  315. $smcFunc['db_free_result']($request);
  316. }
  317.  
  318. /**
  319. * JS for mentions while posting
  320. *
  321. * @return void
  322. */
  323. function mentions_post_scripts()
  324. {
  325. global $settings, $context;
  326.  
  327. if (!allowedTo('mention_member'))
  328. return;
  329.  
  330. $context['insert_after_template'] .= '
  331. <script type="text/javascript">
  332. var jquery_url = "//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js";
  333. var atwho_url = "' . $settings['default_theme_url'] . '/scripts/jquery.atwho.js";
  334. var smf_sessid = "' . $context['session_id'] . '";
  335. var smf_sessvar = "' . $context['session_var'] . '";
  336. </script>
  337. <script type="text/javascript" src="' . $settings['default_theme_url'] . '/scripts/mentions.js"></script>
  338. <link rel="stylesheet" type="text/css" href="' . (file_exists($settings['theme_dir'] . '/css/mentions.css') ? $settings['theme_url'] : $settings['default_theme_url']) . '/css/mentions.css" />';
  339. }
  340.  
  341. /**
  342. * Scheduled task for removing mentions older than x days
  343. *
  344. * @return void
  345. */
  346. function scheduled_removeMentions()
  347. {
  348. global $modSettings, $smcFunc;
  349.  
  350. $smcFunc['db_query']('', '
  351. DELETE FROM {db_prefix}log_mentions
  352. WHERE time < {int:time}
  353. AND unseen = 0',
  354. array(
  355. 'time' => time() - ((!empty($modSettings['mentions_remove_days']) ? $modSettings['mentions_remove_days'] : 0) * 86400),
  356. )
  357. );
  358. }
  359.  
  360. /**
  361. * Handles the profile area for mentions
  362. *
  363. * @param int $memID
  364. * @return void
  365. */
  366. function Mentions_Profile($memID)
  367. {
  368. global $smcFunc, $sourcedir, $txt, $context, $modSettings, $user_info, $scripturl;
  369.  
  370. loadLanguage('Mentions');
  371.  
  372. if (!empty($_POST['save']) && $user_info['id'] == $memID)
  373. updateMemberData($memID, array('email_mentions' => (bool) !empty($_POST['email_mentions'])));
  374.  
  375. if ($memID == $user_info['id'])
  376. {
  377. $smcFunc['db_query']('', '
  378. UPDATE {db_prefix}log_mentions
  379. SET unseen = 0
  380. WHERE id_mentioned = {int:member}',
  381. array(
  382. 'member' => $user_info['id'],
  383. )
  384. );
  385. updateMemberData($user_info['id'], array('unread_mentions' => 0));
  386. }
  387.  
  388. $request = $smcFunc['db_query']('', '
  389. SELECT emaiL_mentions
  390. FROM {db_prefix}members
  391. WHERE id_member = {int:member}',
  392. array(
  393. 'member' => $memID,
  394. )
  395. );
  396. list ($email_mentions) = $smcFunc['db_fetch_row']($request);
  397. $smcFunc['db_free_result'];
  398.  
  399. // Set the options for the list component.
  400. $listOptions = array(
  401. 'id' => 'mentions_list',
  402. 'title' => sprintf($txt['mentions_profile_title'], $context['member']['name']),
  403. 'items_per_page' => 20,
  404. 'base_href' => $scripturl . '?action=profile;area=tracking;sa=user;u=' . $memID,
  405. 'default_sort_col' => 'time',
  406. 'get_items' => array(
  407. 'function' => 'list_getMentions',
  408. 'params' => array(
  409. 'lm.id_mentioned = {int:current_member}',
  410. array('current_member' => $memID),
  411. ),
  412. ),
  413. 'get_count' => array(
  414. 'function' => 'list_getMentionsCount',
  415. 'params' => array(
  416. 'lm.id_mentioned = {int:current_member}',
  417. array('current_member' => $memID),
  418. ),
  419. ),
  420. 'columns' => array(
  421. 'subject' => array(
  422. 'header' => array(
  423. 'value' => $txt['mentions_post_subject'],
  424. ),
  425. 'data' => array(
  426. 'sprintf' => array(
  427. 'format' => '<a href="' . $scripturl . '?msg=%d">%s</a>',
  428. 'params' => array(
  429. 'id_post' => false,
  430. 'subject' => false,
  431. ),
  432. ),
  433. ),
  434. 'sort' => array(
  435. 'default' => 'msg.subject DESC',
  436. 'reverse' => 'msg.subject ASC',
  437. ),
  438. ),
  439. 'by' => array(
  440. 'header' => array(
  441. 'value' => $txt['mentions_member'],
  442. ),
  443. 'data' => array(
  444. 'sprintf' => array(
  445. 'format' => '<a href="' . $scripturl . '?action=profile;u=%d">%s</a>',
  446. 'params' => array(
  447. 'id_member' => false,
  448. 'real_name' => false,
  449. ),
  450. ),
  451. ),
  452. ),
  453. 'time' => array(
  454. 'header' => array(
  455. 'value' => $txt['mentions_post_time'],
  456. ),
  457. 'data' => array(
  458. 'db' => 'time',
  459. ),
  460. 'sort' => array(
  461. 'default' => 'lm.time DESC',
  462. 'reverse' => 'lm.time ASC',
  463. ),
  464. ),
  465. ),
  466. 'form' => array(
  467. 'href' => $scripturl . '?action=profile;area=mentions',
  468. 'include_sort' => true,
  469. 'include_start' => true,
  470. 'hidden_fields' => array(
  471. 'save' => true,
  472. ),
  473. ),
  474. 'additional_rows' => array(
  475. array(
  476. 'position' => 'bottom_of_list',
  477. 'value' => '<label for="email_mentions">' . $txt['email_mentions'] . ':</label> <input type="checkbox" name="email_mentions" value="1" onchange="this.form.submit()"' . ($email_mentions ? ' checked' : '') . ' />',
  478. ),
  479. ),
  480. );
  481.  
  482. // Create the list for viewing.
  483. require_once($sourcedir . '/Subs-List.php');
  484. createList($listOptions);
  485.  
  486. $context['default_list'] = 'mentions_list';
  487. $context['sub_template'] = 'show_list';
  488. }
  489.  
  490. function list_getMentionsCount($where, $where_vars = array())
  491. {
  492. global $smcFunc;
  493.  
  494. $request = $smcFunc['db_query']('', '
  495. SELECT COUNT(lm.id_mentioned) AS mentions_count
  496. FROM {db_prefix}log_mentions AS lm
  497. WHERE ' . $where,
  498. $where_vars
  499. );
  500. list ($count) = $smcFunc['db_fetch_row']($request);
  501. $smcFunc['db_free_result']($request);
  502.  
  503. return $count;
  504. }
  505.  
  506. function list_getMentions($start, $items_per_page, $sort, $where, $where_vars = array())
  507. {
  508. global $smcFunc, $txt, $scripturl;
  509.  
  510. // Get a list of error messages from this ip (range).
  511. $request = $smcFunc['db_query']('', '
  512. SELECT
  513. lm.id_post, lm.id_mentioned, lm.id_member, lm.time,
  514. mem.real_name, msg.subject
  515. FROM {db_prefix}log_mentions AS lm
  516. INNER JOIN {db_prefix}members AS mem ON (mem.id_member = lm.id_member)
  517. INNER JOIN {db_prefix}messages AS msg ON (msg.id_msg = lm.id_post)
  518. INNER JOIN {db_prefix}topics AS t ON (t.id_topic = msg.id_topic)
  519. INNER JOIN {db_prefix}boards AS b ON (b.id_board = t.id_board)
  520. WHERE ' . $where . '
  521. AND {query_see_board}
  522. AND msg.approved = 1
  523. ORDER BY ' . $sort . '
  524. LIMIT ' . $start . ', ' . $items_per_page,
  525. $where_vars
  526. );
  527. $mentions = array();
  528. while ($row = $smcFunc['db_fetch_assoc']($request))
  529. {
  530. $row['time'] = timeformat($row['time']);
  531. $mentions[] = $row;
  532. }
  533. $smcFunc['db_free_result']($request);
  534.  
  535. return $mentions;
  536. }
  537.  
  538. /**
  539. * Hook callback for integrate_register
  540. *
  541. * @param array &$register_options
  542. * @param array &$theme_vars
  543. * @return void
  544. */
  545. function mentions_register(array &$register_options, array &$theme_vars)
  546. {
  547. global $modSettings;
  548. $register_options['register_vars']['email_mentions'] = !empty($modSettings['mentions_email_default']) ? 1 : 0;
  549. }
  550.  
  551. /**
  552. * Function for managing mention's settings
  553. *
  554. * @param bool $return_config
  555. * @return array
  556. */
  557. function ModifyMentionsSettings($return_config = false)
  558. {
  559. global $txt, $scripturl, $context, $settings, $sc, $modSettings, $smcFunc;
  560.  
  561. loadLanguage('Mentions');
  562.  
  563. $modSettings['mentions_email_default_now'] = 0;
  564.  
  565. $config_vars = array(
  566. array('desc', 'mentions_permissions_notice'),
  567. array('int', 'mentions_remove_days'),
  568. array('check', 'mentions_email_default'),
  569. array('check', 'mentions_email_default_now'),
  570. );
  571.  
  572. if ($return_config)
  573. return $config_vars;
  574.  
  575. // Saving?
  576. if (isset($_GET['save']))
  577. {
  578. checkSession();
  579.  
  580. if (!empty($_POST['mentions_email_default_now']))
  581. $smcFunc['db_query']('', '
  582. UPDATE {db_prefix}members
  583. SET email_mentions = 1',
  584. array()
  585. );
  586.  
  587. saveDBSettings($config_vars);
  588. redirectexit('action=admin;area=modsettings;sa=mentions');
  589. }
  590.  
  591. $context['post_url'] = $scripturl . '?action=admin;area=modsettings;save;sa=mentions';
  592. $context['settings_title'] = $txt['mentions'];
  593.  
  594. prepareDBSettingContext($config_vars);
  595. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement