PageRenderTime 384ms CodeModel.GetById 18ms RepoModel.GetById 1ms app.codeStats 0ms

/sources/subs/Topic.subs.php

https://github.com/Arantor/Elkarte
PHP | 1355 lines | 999 code | 124 blank | 232 comment | 85 complexity | b8696ea0be8783c3ea86219d1771ea1b 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 contains functions for dealing with topics. Low-level functions,
  16. * i.e. database operations needed to perform.
  17. * These functions do NOT make permissions checks. (they assume those were
  18. * already made).
  19. *
  20. */
  21. if (!defined('ELKARTE'))
  22. die('No access...');
  23. /**
  24. * Removes the passed id_topic's. (permissions are NOT checked here!).
  25. *
  26. * @param array/int $topics The topics to remove (can be an id or an array of ids).
  27. * @param bool $decreasePostCount if true users' post count will be reduced
  28. * @param bool $ignoreRecycling if true topics are not moved to the recycle board (if it exists).
  29. */
  30. function removeTopics($topics, $decreasePostCount = true, $ignoreRecycling = false)
  31. {
  32. global $modSettings, $smcFunc;
  33. // Nothing to do?
  34. if (empty($topics))
  35. return;
  36. // Only a single topic.
  37. if (is_numeric($topics))
  38. $topics = array($topics);
  39. // Decrease the post counts.
  40. if ($decreasePostCount)
  41. {
  42. $requestMembers = $smcFunc['db_query']('', '
  43. SELECT m.id_member, COUNT(*) AS posts
  44. FROM {db_prefix}messages AS m
  45. INNER JOIN {db_prefix}boards AS b ON (b.id_board = m.id_board)
  46. WHERE m.id_topic IN ({array_int:topics})
  47. AND m.icon != {string:recycled}
  48. AND b.count_posts = {int:do_count_posts}
  49. AND m.approved = {int:is_approved}
  50. GROUP BY m.id_member',
  51. array(
  52. 'do_count_posts' => 0,
  53. 'recycled' => 'recycled',
  54. 'topics' => $topics,
  55. 'is_approved' => 1,
  56. )
  57. );
  58. if ($smcFunc['db_num_rows']($requestMembers) > 0)
  59. {
  60. while ($rowMembers = $smcFunc['db_fetch_assoc']($requestMembers))
  61. updateMemberData($rowMembers['id_member'], array('posts' => 'posts - ' . $rowMembers['posts']));
  62. }
  63. $smcFunc['db_free_result']($requestMembers);
  64. }
  65. // Recycle topics that aren't in the recycle board...
  66. if (!empty($modSettings['recycle_enable']) && $modSettings['recycle_board'] > 0 && !$ignoreRecycling)
  67. {
  68. $request = $smcFunc['db_query']('', '
  69. SELECT id_topic, id_board, unapproved_posts, approved
  70. FROM {db_prefix}topics
  71. WHERE id_topic IN ({array_int:topics})
  72. AND id_board != {int:recycle_board}
  73. LIMIT ' . count($topics),
  74. array(
  75. 'recycle_board' => $modSettings['recycle_board'],
  76. 'topics' => $topics,
  77. )
  78. );
  79. if ($smcFunc['db_num_rows']($request) > 0)
  80. {
  81. // Get topics that will be recycled.
  82. $recycleTopics = array();
  83. while ($row = $smcFunc['db_fetch_assoc']($request))
  84. {
  85. if (function_exists('apache_reset_timeout'))
  86. @apache_reset_timeout();
  87. $recycleTopics[] = $row['id_topic'];
  88. // Set the id_previous_board for this topic - and make it not sticky.
  89. $smcFunc['db_query']('', '
  90. UPDATE {db_prefix}topics
  91. SET id_previous_board = {int:id_previous_board}, is_sticky = {int:not_sticky}
  92. WHERE id_topic = {int:id_topic}',
  93. array(
  94. 'id_previous_board' => $row['id_board'],
  95. 'id_topic' => $row['id_topic'],
  96. 'not_sticky' => 0,
  97. )
  98. );
  99. }
  100. $smcFunc['db_free_result']($request);
  101. // Mark recycled topics as recycled.
  102. $smcFunc['db_query']('', '
  103. UPDATE {db_prefix}messages
  104. SET icon = {string:recycled}
  105. WHERE id_topic IN ({array_int:recycle_topics})',
  106. array(
  107. 'recycle_topics' => $recycleTopics,
  108. 'recycled' => 'recycled',
  109. )
  110. );
  111. // Move the topics to the recycle board.
  112. require_once(SUBSDIR . '/Topic.subs.php');
  113. moveTopics($recycleTopics, $modSettings['recycle_board']);
  114. // Close reports that are being recycled.
  115. require_once(SUBSDIR . '/Moderation.subs.php');
  116. $smcFunc['db_query']('', '
  117. UPDATE {db_prefix}log_reported
  118. SET closed = {int:is_closed}
  119. WHERE id_topic IN ({array_int:recycle_topics})',
  120. array(
  121. 'recycle_topics' => $recycleTopics,
  122. 'is_closed' => 1,
  123. )
  124. );
  125. updateSettings(array('last_mod_report_action' => time()));
  126. recountOpenReports();
  127. // Topics that were recycled don't need to be deleted, so subtract them.
  128. $topics = array_diff($topics, $recycleTopics);
  129. }
  130. else
  131. $smcFunc['db_free_result']($request);
  132. }
  133. // Still topics left to delete?
  134. if (empty($topics))
  135. return;
  136. $adjustBoards = array();
  137. // Find out how many posts we are deleting.
  138. $request = $smcFunc['db_query']('', '
  139. SELECT id_board, approved, COUNT(*) AS num_topics, SUM(unapproved_posts) AS unapproved_posts,
  140. SUM(num_replies) AS num_replies
  141. FROM {db_prefix}topics
  142. WHERE id_topic IN ({array_int:topics})
  143. GROUP BY id_board, approved',
  144. array(
  145. 'topics' => $topics,
  146. )
  147. );
  148. while ($row = $smcFunc['db_fetch_assoc']($request))
  149. {
  150. if (!isset($adjustBoards[$row['id_board']]['num_posts']))
  151. {
  152. $adjustBoards[$row['id_board']] = array(
  153. 'num_posts' => 0,
  154. 'num_topics' => 0,
  155. 'unapproved_posts' => 0,
  156. 'unapproved_topics' => 0,
  157. 'id_board' => $row['id_board']
  158. );
  159. }
  160. // Posts = (num_replies + 1) for each approved topic.
  161. $adjustBoards[$row['id_board']]['num_posts'] += $row['num_replies'] + ($row['approved'] ? $row['num_topics'] : 0);
  162. $adjustBoards[$row['id_board']]['unapproved_posts'] += $row['unapproved_posts'];
  163. // Add the topics to the right type.
  164. if ($row['approved'])
  165. $adjustBoards[$row['id_board']]['num_topics'] += $row['num_topics'];
  166. else
  167. $adjustBoards[$row['id_board']]['unapproved_topics'] += $row['num_topics'];
  168. }
  169. $smcFunc['db_free_result']($request);
  170. // Decrease the posts/topics...
  171. foreach ($adjustBoards as $stats)
  172. {
  173. if (function_exists('apache_reset_timeout'))
  174. @apache_reset_timeout();
  175. $smcFunc['db_query']('', '
  176. UPDATE {db_prefix}boards
  177. SET
  178. num_posts = CASE WHEN {int:num_posts} > num_posts THEN 0 ELSE num_posts - {int:num_posts} END,
  179. num_topics = CASE WHEN {int:num_topics} > num_topics THEN 0 ELSE num_topics - {int:num_topics} END,
  180. unapproved_posts = CASE WHEN {int:unapproved_posts} > unapproved_posts THEN 0 ELSE unapproved_posts - {int:unapproved_posts} END,
  181. unapproved_topics = CASE WHEN {int:unapproved_topics} > unapproved_topics THEN 0 ELSE unapproved_topics - {int:unapproved_topics} END
  182. WHERE id_board = {int:id_board}',
  183. array(
  184. 'id_board' => $stats['id_board'],
  185. 'num_posts' => $stats['num_posts'],
  186. 'num_topics' => $stats['num_topics'],
  187. 'unapproved_posts' => $stats['unapproved_posts'],
  188. 'unapproved_topics' => $stats['unapproved_topics'],
  189. )
  190. );
  191. }
  192. // Remove Polls.
  193. $request = $smcFunc['db_query']('', '
  194. SELECT id_poll
  195. FROM {db_prefix}topics
  196. WHERE id_topic IN ({array_int:topics})
  197. AND id_poll > {int:no_poll}
  198. LIMIT ' . count($topics),
  199. array(
  200. 'no_poll' => 0,
  201. 'topics' => $topics,
  202. )
  203. );
  204. $polls = array();
  205. while ($row = $smcFunc['db_fetch_assoc']($request))
  206. $polls[] = $row['id_poll'];
  207. $smcFunc['db_free_result']($request);
  208. if (!empty($polls))
  209. {
  210. $smcFunc['db_query']('', '
  211. DELETE FROM {db_prefix}polls
  212. WHERE id_poll IN ({array_int:polls})',
  213. array(
  214. 'polls' => $polls,
  215. )
  216. );
  217. $smcFunc['db_query']('', '
  218. DELETE FROM {db_prefix}poll_choices
  219. WHERE id_poll IN ({array_int:polls})',
  220. array(
  221. 'polls' => $polls,
  222. )
  223. );
  224. $smcFunc['db_query']('', '
  225. DELETE FROM {db_prefix}log_polls
  226. WHERE id_poll IN ({array_int:polls})',
  227. array(
  228. 'polls' => $polls,
  229. )
  230. );
  231. }
  232. // Get rid of the attachment(s), if they exist.
  233. require_once(SUBSDIR . '/Attachments.subs.php');
  234. $attachmentQuery = array(
  235. 'attachment_type' => 0,
  236. 'id_topic' => $topics,
  237. );
  238. removeAttachments($attachmentQuery, 'messages');
  239. // Delete possible search index entries.
  240. if (!empty($modSettings['search_custom_index_config']))
  241. {
  242. $customIndexSettings = unserialize($modSettings['search_custom_index_config']);
  243. $words = array();
  244. $messages = array();
  245. $request = $smcFunc['db_query']('', '
  246. SELECT id_msg, body
  247. FROM {db_prefix}messages
  248. WHERE id_topic IN ({array_int:topics})',
  249. array(
  250. 'topics' => $topics,
  251. )
  252. );
  253. while ($row = $smcFunc['db_fetch_assoc']($request))
  254. {
  255. if (function_exists('apache_reset_timeout'))
  256. @apache_reset_timeout();
  257. $words = array_merge($words, text2words($row['body'], $customIndexSettings['bytes_per_word'], true));
  258. $messages[] = $row['id_msg'];
  259. }
  260. $smcFunc['db_free_result']($request);
  261. $words = array_unique($words);
  262. if (!empty($words) && !empty($messages))
  263. $smcFunc['db_query']('', '
  264. DELETE FROM {db_prefix}log_search_words
  265. WHERE id_word IN ({array_int:word_list})
  266. AND id_msg IN ({array_int:message_list})',
  267. array(
  268. 'word_list' => $words,
  269. 'message_list' => $messages,
  270. )
  271. );
  272. }
  273. // Delete anything related to the topic.
  274. $smcFunc['db_query']('', '
  275. DELETE FROM {db_prefix}messages
  276. WHERE id_topic IN ({array_int:topics})',
  277. array(
  278. 'topics' => $topics,
  279. )
  280. );
  281. $smcFunc['db_query']('', '
  282. DELETE FROM {db_prefix}calendar
  283. WHERE id_topic IN ({array_int:topics})',
  284. array(
  285. 'topics' => $topics,
  286. )
  287. );
  288. $smcFunc['db_query']('', '
  289. DELETE FROM {db_prefix}log_topics
  290. WHERE id_topic IN ({array_int:topics})',
  291. array(
  292. 'topics' => $topics,
  293. )
  294. );
  295. $smcFunc['db_query']('', '
  296. DELETE FROM {db_prefix}log_notify
  297. WHERE id_topic IN ({array_int:topics})',
  298. array(
  299. 'topics' => $topics,
  300. )
  301. );
  302. $smcFunc['db_query']('', '
  303. DELETE FROM {db_prefix}topics
  304. WHERE id_topic IN ({array_int:topics})',
  305. array(
  306. 'topics' => $topics,
  307. )
  308. );
  309. $smcFunc['db_query']('', '
  310. DELETE FROM {db_prefix}log_search_subjects
  311. WHERE id_topic IN ({array_int:topics})',
  312. array(
  313. 'topics' => $topics,
  314. )
  315. );
  316. // Maybe there's a mod that wants to delete topic related data of its own
  317. call_integration_hook('integrate_remove_topics', array($topics));
  318. // Update the totals...
  319. updateStats('message');
  320. updateStats('topic');
  321. updateSettings(array(
  322. 'calendar_updated' => time(),
  323. ));
  324. require_once(SUBSDIR . '/Post.subs.php');
  325. $updates = array();
  326. foreach ($adjustBoards as $stats)
  327. $updates[] = $stats['id_board'];
  328. updateLastMessages($updates);
  329. }
  330. /**
  331. * Moves one or more topics to a specific board. (doesn't check permissions.)
  332. * Determines the source boards for the supplied topics
  333. * Handles the moving of mark_read data
  334. * Updates the posts count of the affected boards
  335. *
  336. * @param type $topics
  337. * @param type $toBoard
  338. * @return type
  339. */
  340. function moveTopics($topics, $toBoard)
  341. {
  342. global $user_info, $modSettings, $smcFunc;
  343. // Empty array?
  344. if (empty($topics))
  345. return;
  346. // Only a single topic.
  347. if (is_numeric($topics))
  348. $topics = array($topics);
  349. $num_topics = count($topics);
  350. $fromBoards = array();
  351. // Destination board empty or equal to 0?
  352. if (empty($toBoard))
  353. return;
  354. // Are we moving to the recycle board?
  355. $isRecycleDest = !empty($modSettings['recycle_enable']) && $modSettings['recycle_board'] == $toBoard;
  356. // Determine the source boards...
  357. $request = $smcFunc['db_query']('', '
  358. SELECT id_board, approved, COUNT(*) AS num_topics, SUM(unapproved_posts) AS unapproved_posts,
  359. SUM(num_replies) AS num_replies
  360. FROM {db_prefix}topics
  361. WHERE id_topic IN ({array_int:topics})
  362. GROUP BY id_board, approved',
  363. array(
  364. 'topics' => $topics,
  365. )
  366. );
  367. // Num of rows = 0 -> no topics found. Num of rows > 1 -> topics are on multiple boards.
  368. if ($smcFunc['db_num_rows']($request) == 0)
  369. return;
  370. while ($row = $smcFunc['db_fetch_assoc']($request))
  371. {
  372. if (!isset($fromBoards[$row['id_board']]['num_posts']))
  373. {
  374. $fromBoards[$row['id_board']] = array(
  375. 'num_posts' => 0,
  376. 'num_topics' => 0,
  377. 'unapproved_posts' => 0,
  378. 'unapproved_topics' => 0,
  379. 'id_board' => $row['id_board']
  380. );
  381. }
  382. // Posts = (num_replies + 1) for each approved topic.
  383. $fromBoards[$row['id_board']]['num_posts'] += $row['num_replies'] + ($row['approved'] ? $row['num_topics'] : 0);
  384. $fromBoards[$row['id_board']]['unapproved_posts'] += $row['unapproved_posts'];
  385. // Add the topics to the right type.
  386. if ($row['approved'])
  387. $fromBoards[$row['id_board']]['num_topics'] += $row['num_topics'];
  388. else
  389. $fromBoards[$row['id_board']]['unapproved_topics'] += $row['num_topics'];
  390. }
  391. $smcFunc['db_free_result']($request);
  392. // Move over the mark_read data. (because it may be read and now not by some!)
  393. $SaveAServer = max(0, $modSettings['maxMsgID'] - 50000);
  394. $request = $smcFunc['db_query']('', '
  395. SELECT lmr.id_member, lmr.id_msg, t.id_topic, IFNULL(lt.disregarded, 0) as disregarded
  396. FROM {db_prefix}topics AS t
  397. INNER JOIN {db_prefix}log_mark_read AS lmr ON (lmr.id_board = t.id_board
  398. AND lmr.id_msg > t.id_first_msg AND lmr.id_msg > {int:protect_lmr_msg})
  399. LEFT JOIN {db_prefix}log_topics AS lt ON (lt.id_topic = t.id_topic AND lt.id_member = lmr.id_member)
  400. WHERE t.id_topic IN ({array_int:topics})
  401. AND lmr.id_msg > IFNULL(lt.id_msg, 0)',
  402. array(
  403. 'protect_lmr_msg' => $SaveAServer,
  404. 'topics' => $topics,
  405. )
  406. );
  407. $log_topics = array();
  408. while ($row = $smcFunc['db_fetch_assoc']($request))
  409. {
  410. $log_topics[] = array($row['id_member'], $row['id_topic'], $row['id_msg'], $row['disregarded']);
  411. // Prevent queries from getting too big. Taking some steam off.
  412. if (count($log_topics) > 500)
  413. {
  414. markTopicsRead($log_topics, true);
  415. $log_topics = array();
  416. }
  417. }
  418. $smcFunc['db_free_result']($request);
  419. // Now that we have all the topics that *should* be marked read, and by which members...
  420. if (!empty($log_topics))
  421. {
  422. // Insert that information into the database!
  423. markTopicsRead($log_topics, true);
  424. }
  425. // Update the number of posts on each board.
  426. $totalTopics = 0;
  427. $totalPosts = 0;
  428. $totalUnapprovedTopics = 0;
  429. $totalUnapprovedPosts = 0;
  430. foreach ($fromBoards as $stats)
  431. {
  432. $smcFunc['db_query']('', '
  433. UPDATE {db_prefix}boards
  434. SET
  435. num_posts = CASE WHEN {int:num_posts} > num_posts THEN 0 ELSE num_posts - {int:num_posts} END,
  436. num_topics = CASE WHEN {int:num_topics} > num_topics THEN 0 ELSE num_topics - {int:num_topics} END,
  437. unapproved_posts = CASE WHEN {int:unapproved_posts} > unapproved_posts THEN 0 ELSE unapproved_posts - {int:unapproved_posts} END,
  438. unapproved_topics = CASE WHEN {int:unapproved_topics} > unapproved_topics THEN 0 ELSE unapproved_topics - {int:unapproved_topics} END
  439. WHERE id_board = {int:id_board}',
  440. array(
  441. 'id_board' => $stats['id_board'],
  442. 'num_posts' => $stats['num_posts'],
  443. 'num_topics' => $stats['num_topics'],
  444. 'unapproved_posts' => $stats['unapproved_posts'],
  445. 'unapproved_topics' => $stats['unapproved_topics'],
  446. )
  447. );
  448. $totalTopics += $stats['num_topics'];
  449. $totalPosts += $stats['num_posts'];
  450. $totalUnapprovedTopics += $stats['unapproved_topics'];
  451. $totalUnapprovedPosts += $stats['unapproved_posts'];
  452. }
  453. $smcFunc['db_query']('', '
  454. UPDATE {db_prefix}boards
  455. SET
  456. num_topics = num_topics + {int:total_topics},
  457. num_posts = num_posts + {int:total_posts},' . ($isRecycleDest ? '
  458. unapproved_posts = {int:no_unapproved}, unapproved_topics = {int:no_unapproved}' : '
  459. unapproved_posts = unapproved_posts + {int:total_unapproved_posts},
  460. unapproved_topics = unapproved_topics + {int:total_unapproved_topics}') . '
  461. WHERE id_board = {int:id_board}',
  462. array(
  463. 'id_board' => $toBoard,
  464. 'total_topics' => $totalTopics,
  465. 'total_posts' => $totalPosts,
  466. 'total_unapproved_topics' => $totalUnapprovedTopics,
  467. 'total_unapproved_posts' => $totalUnapprovedPosts,
  468. 'no_unapproved' => 0,
  469. )
  470. );
  471. // Move the topic. Done. :P
  472. $smcFunc['db_query']('', '
  473. UPDATE {db_prefix}topics
  474. SET id_board = {int:id_board}' . ($isRecycleDest ? ',
  475. unapproved_posts = {int:no_unapproved}, approved = {int:is_approved}' : '') . '
  476. WHERE id_topic IN ({array_int:topics})',
  477. array(
  478. 'id_board' => $toBoard,
  479. 'topics' => $topics,
  480. 'is_approved' => 1,
  481. 'no_unapproved' => 0,
  482. )
  483. );
  484. // If this was going to the recycle bin, check what messages are being recycled, and remove them from the queue.
  485. if ($isRecycleDest && ($totalUnapprovedTopics || $totalUnapprovedPosts))
  486. {
  487. $request = $smcFunc['db_query']('', '
  488. SELECT id_msg
  489. FROM {db_prefix}messages
  490. WHERE id_topic IN ({array_int:topics})
  491. and approved = {int:not_approved}',
  492. array(
  493. 'topics' => $topics,
  494. 'not_approved' => 0,
  495. )
  496. );
  497. $approval_msgs = array();
  498. while ($row = $smcFunc['db_fetch_assoc']($request))
  499. $approval_msgs[] = $row['id_msg'];
  500. $smcFunc['db_free_result']($request);
  501. // Empty the approval queue for these, as we're going to approve them next.
  502. if (!empty($approval_msgs))
  503. $smcFunc['db_query']('', '
  504. DELETE FROM {db_prefix}approval_queue
  505. WHERE id_msg IN ({array_int:message_list})
  506. AND id_attach = {int:id_attach}',
  507. array(
  508. 'message_list' => $approval_msgs,
  509. 'id_attach' => 0,
  510. )
  511. );
  512. // Get all the current max and mins.
  513. $request = $smcFunc['db_query']('', '
  514. SELECT id_topic, id_first_msg, id_last_msg
  515. FROM {db_prefix}topics
  516. WHERE id_topic IN ({array_int:topics})',
  517. array(
  518. 'topics' => $topics,
  519. )
  520. );
  521. $topicMaxMin = array();
  522. while ($row = $smcFunc['db_fetch_assoc']($request))
  523. {
  524. $topicMaxMin[$row['id_topic']] = array(
  525. 'min' => $row['id_first_msg'],
  526. 'max' => $row['id_last_msg'],
  527. );
  528. }
  529. $smcFunc['db_free_result']($request);
  530. // Check the MAX and MIN are correct.
  531. $request = $smcFunc['db_query']('', '
  532. SELECT id_topic, MIN(id_msg) AS first_msg, MAX(id_msg) AS last_msg
  533. FROM {db_prefix}messages
  534. WHERE id_topic IN ({array_int:topics})
  535. GROUP BY id_topic',
  536. array(
  537. 'topics' => $topics,
  538. )
  539. );
  540. while ($row = $smcFunc['db_fetch_assoc']($request))
  541. {
  542. // If not, update.
  543. if ($row['first_msg'] != $topicMaxMin[$row['id_topic']]['min'] || $row['last_msg'] != $topicMaxMin[$row['id_topic']]['max'])
  544. $smcFunc['db_query']('', '
  545. UPDATE {db_prefix}topics
  546. SET id_first_msg = {int:first_msg}, id_last_msg = {int:last_msg}
  547. WHERE id_topic = {int:selected_topic}',
  548. array(
  549. 'first_msg' => $row['first_msg'],
  550. 'last_msg' => $row['last_msg'],
  551. 'selected_topic' => $row['id_topic'],
  552. )
  553. );
  554. }
  555. $smcFunc['db_free_result']($request);
  556. }
  557. $smcFunc['db_query']('', '
  558. UPDATE {db_prefix}messages
  559. SET id_board = {int:id_board}' . ($isRecycleDest ? ',approved = {int:is_approved}' : '') . '
  560. WHERE id_topic IN ({array_int:topics})',
  561. array(
  562. 'id_board' => $toBoard,
  563. 'topics' => $topics,
  564. 'is_approved' => 1,
  565. )
  566. );
  567. $smcFunc['db_query']('', '
  568. UPDATE {db_prefix}log_reported
  569. SET id_board = {int:id_board}
  570. WHERE id_topic IN ({array_int:topics})',
  571. array(
  572. 'id_board' => $toBoard,
  573. 'topics' => $topics,
  574. )
  575. );
  576. $smcFunc['db_query']('', '
  577. UPDATE {db_prefix}calendar
  578. SET id_board = {int:id_board}
  579. WHERE id_topic IN ({array_int:topics})',
  580. array(
  581. 'id_board' => $toBoard,
  582. 'topics' => $topics,
  583. )
  584. );
  585. // Mark target board as seen, if it was already marked as seen before.
  586. $request = $smcFunc['db_query']('', '
  587. SELECT (IFNULL(lb.id_msg, 0) >= b.id_msg_updated) AS isSeen
  588. FROM {db_prefix}boards AS b
  589. LEFT JOIN {db_prefix}log_boards AS lb ON (lb.id_board = b.id_board AND lb.id_member = {int:current_member})
  590. WHERE b.id_board = {int:id_board}',
  591. array(
  592. 'current_member' => $user_info['id'],
  593. 'id_board' => $toBoard,
  594. )
  595. );
  596. list ($isSeen) = $smcFunc['db_fetch_row']($request);
  597. $smcFunc['db_free_result']($request);
  598. if (!empty($isSeen) && !$user_info['is_guest'])
  599. {
  600. $smcFunc['db_insert']('replace',
  601. '{db_prefix}log_boards',
  602. array('id_board' => 'int', 'id_member' => 'int', 'id_msg' => 'int'),
  603. array($toBoard, $user_info['id'], $modSettings['maxMsgID']),
  604. array('id_board', 'id_member')
  605. );
  606. }
  607. // Update the cache?
  608. if (!empty($modSettings['cache_enable']) && $modSettings['cache_enable'] >= 3)
  609. foreach ($topics as $topic_id)
  610. cache_put_data('topic_board-' . $topic_id, null, 120);
  611. require_once(SUBSDIR . '/Post.subs.php');
  612. $updates = array_keys($fromBoards);
  613. $updates[] = $toBoard;
  614. updateLastMessages(array_unique($updates));
  615. // Update 'em pesky stats.
  616. updateStats('topic');
  617. updateStats('message');
  618. updateSettings(array(
  619. 'calendar_updated' => time(),
  620. ));
  621. }
  622. /**
  623. * Called after a topic is moved to update $board_link and $topic_link to point to new location
  624. */
  625. function moveTopicConcurrence()
  626. {
  627. global $board, $topic, $smcFunc, $scripturl;
  628. if (isset($_GET['current_board']))
  629. $move_from = (int) $_GET['current_board'];
  630. if (empty($move_from) || empty($board) || empty($topic))
  631. return true;
  632. if ($move_from == $board)
  633. return true;
  634. else
  635. {
  636. $request = $smcFunc['db_query']('', '
  637. SELECT m.subject, b.name
  638. FROM {db_prefix}topics as t
  639. LEFT JOIN {db_prefix}boards AS b ON (t.id_board = b.id_board)
  640. LEFT JOIN {db_prefix}messages AS m ON (t.id_first_msg = m.id_msg)
  641. WHERE t.id_topic = {int:topic_id}
  642. LIMIT 1',
  643. array(
  644. 'topic_id' => $topic,
  645. )
  646. );
  647. list($topic_subject, $board_name) = $smcFunc['db_fetch_row']($request);
  648. $smcFunc['db_free_result']($request);
  649. $board_link = '<a href="' . $scripturl . '?board=' . $board . '.0">' . $board_name . '</a>';
  650. $topic_link = '<a href="' . $scripturl . '?topic=' . $topic . '.0">' . $topic_subject . '</a>';
  651. fatal_lang_error('topic_already_moved', false, array($topic_link, $board_link));
  652. }
  653. }
  654. /**
  655. * Increase the number of views of this topic.
  656. *
  657. * @param int $id_topic, the topic being viewed or whatnot.
  658. */
  659. function increaseViewCounter($id_topic)
  660. {
  661. global $smcFunc;
  662. $smcFunc['db_query']('', '
  663. UPDATE {db_prefix}topics
  664. SET num_views = num_views + 1
  665. WHERE id_topic = {int:current_topic}',
  666. array(
  667. 'current_topic' => $id_topic,
  668. )
  669. );
  670. }
  671. /**
  672. * Mark topic(s) as read by the given member, at the specified message.
  673. *
  674. * @param array $mark_topics array($id_member, $id_topic, $id_msg)
  675. * @param bool $was_set = false - whether the topic has been previously read by the user
  676. */
  677. function markTopicsRead($mark_topics, $was_set = false)
  678. {
  679. global $smcFunc;
  680. if (!is_array($mark_topics))
  681. return;
  682. $smcFunc['db_insert']($was_set ? 'replace' : 'ignore',
  683. '{db_prefix}log_topics',
  684. array(
  685. 'id_member' => 'int', 'id_topic' => 'int', 'id_msg' => 'int', 'disregarded' => 'int',
  686. ),
  687. $mark_topics,
  688. array('id_member', 'id_topic')
  689. );
  690. }
  691. /**
  692. * Update user notifications for a topic... or the board it's in.
  693. * @todo look at board notification...
  694. *
  695. * @param int $id_topic
  696. * @param int $id_board
  697. */
  698. function updateReadNotificationsFor($id_topic, $id_board)
  699. {
  700. global $smcFunc, $user_info, $context;
  701. // Check for notifications on this topic OR board.
  702. $request = $smcFunc['db_query']('', '
  703. SELECT sent, id_topic
  704. FROM {db_prefix}log_notify
  705. WHERE (id_topic = {int:current_topic} OR id_board = {int:current_board})
  706. AND id_member = {int:current_member}
  707. LIMIT 2',
  708. array(
  709. 'current_board' => $id_board,
  710. 'current_member' => $user_info['id'],
  711. 'current_topic' => $id_topic,
  712. )
  713. );
  714. while ($row = $smcFunc['db_fetch_assoc']($request))
  715. {
  716. // Find if this topic is marked for notification...
  717. if (!empty($row['id_topic']))
  718. $context['is_marked_notify'] = true;
  719. // Only do this once, but mark the notifications as "not sent yet" for next time.
  720. if (!empty($row['sent']))
  721. {
  722. $smcFunc['db_query']('', '
  723. UPDATE {db_prefix}log_notify
  724. SET sent = {int:is_not_sent}
  725. WHERE (id_topic = {int:current_topic} OR id_board = {int:current_board})
  726. AND id_member = {int:current_member}',
  727. array(
  728. 'current_board' => $id_board,
  729. 'current_member' => $user_info['id'],
  730. 'current_topic' => $id_topic,
  731. 'is_not_sent' => 0,
  732. )
  733. );
  734. break;
  735. }
  736. }
  737. $smcFunc['db_free_result']($request);
  738. }
  739. /**
  740. * How many topics are still unread since (last visit)
  741. *
  742. * @param int $id_msg_last_visit
  743. * @return int
  744. */
  745. function getUnreadCountSince($id_board, $id_msg_last_visit)
  746. {
  747. global $smcFunc, $user_info;
  748. $request = $smcFunc['db_query']('', '
  749. SELECT COUNT(*)
  750. FROM {db_prefix}topics AS t
  751. LEFT JOIN {db_prefix}log_boards AS lb ON (lb.id_board = {int:current_board} AND lb.id_member = {int:current_member})
  752. LEFT JOIN {db_prefix}log_topics AS lt ON (lt.id_topic = t.id_topic AND lt.id_member = {int:current_member})
  753. WHERE t.id_board = {int:current_board}
  754. AND t.id_last_msg > IFNULL(lb.id_msg, 0)
  755. AND t.id_last_msg > IFNULL(lt.id_msg, 0)' .
  756. (empty($id_msg_last_visit) ? '' : '
  757. AND t.id_last_msg > {int:id_msg_last_visit}'),
  758. array(
  759. 'current_board' => $id_board,
  760. 'current_member' => $user_info['id'],
  761. 'id_msg_last_visit' => (int) $id_msg_last_visit,
  762. )
  763. );
  764. list ($unread) = $smcFunc['db_fetch_row']($request);
  765. $smcFunc['db_free_result']($request);
  766. return $unread;
  767. }
  768. /**
  769. * Returns whether this member has notification turned on for the specified topic.
  770. *
  771. * @param int $id_member
  772. * @param int $id_topic
  773. * @return bool
  774. */
  775. function hasTopicNotification($id_member, $id_topic)
  776. {
  777. global $smcFunc;
  778. // Find out if they have notification set for this topic already.
  779. $request = $smcFunc['db_query']('', '
  780. SELECT id_member
  781. FROM {db_prefix}log_notify
  782. WHERE id_member = {int:current_member}
  783. AND id_topic = {int:current_topic}
  784. LIMIT 1',
  785. array(
  786. 'current_member' => $id_member,
  787. 'current_topic' => $id_topic,
  788. )
  789. );
  790. $hasNotification = $smcFunc['db_num_rows']($request) != 0;
  791. $smcFunc['db_free_result']($request);
  792. return $hasNotification;
  793. }
  794. /**
  795. * Set topic notification on or off for the given member.
  796. *
  797. * @param int $id_member
  798. * @param int $id_topic
  799. * @param bool $on
  800. */
  801. function setTopicNotification($id_member, $id_topic, $on = false)
  802. {
  803. global $smcFunc;
  804. if ($on)
  805. {
  806. // Attempt to turn notifications on.
  807. $smcFunc['db_insert']('ignore',
  808. '{db_prefix}log_notify',
  809. array('id_member' => 'int', 'id_topic' => 'int'),
  810. array($id_member, $id_topic),
  811. array('id_member', 'id_topic')
  812. );
  813. }
  814. else
  815. {
  816. // Just turn notifications off.
  817. $smcFunc['db_query']('', '
  818. DELETE FROM {db_prefix}log_notify
  819. WHERE id_member = {int:current_member}
  820. AND id_topic = {int:current_topic}',
  821. array(
  822. 'current_member' => $id_member,
  823. 'current_topic' => $id_topic,
  824. )
  825. );
  826. }
  827. }
  828. /**
  829. * Get the previous topic from where we are.
  830. *
  831. * @param int $id_topic origin topic id
  832. * @param int $id_board board id
  833. * @param int $id_member = 0 member id
  834. * @param bool $includeUnapproved = false whether to include unapproved topics
  835. * @param bool $includeStickies = true whether to include sticky topics
  836. */
  837. function previousTopic($id_topic, $id_board, $id_member = 0, $includeUnapproved = false, $includeStickies = true)
  838. {
  839. return topicPointer($id_topic, $id_board, false, $id_member = 0, $includeUnapproved = false, $includeStickies = true);
  840. }
  841. /**
  842. * Get the next topic from where we are.
  843. *
  844. * @param int $id_topic origin topic id
  845. * @param int $id_board board id
  846. * @param int $id_member = 0 member id
  847. * @param bool $includeUnapproved = false whether to include unapproved topics
  848. * @param bool $includeStickies = true whether to include sticky topics
  849. */
  850. function nextTopic($id_topic, $id_board, $id_member = 0, $includeUnapproved = false, $includeStickies = true)
  851. {
  852. return topicPointer($id_topic, $id_board, true, $id_member = 0, $includeUnapproved = false, $includeStickies = true);
  853. }
  854. /**
  855. * Advance topic pointer.
  856. * (in either direction)
  857. * This function is used by previousTopic() and nextTopic()
  858. * The boolean parameter $next determines direction.
  859. *
  860. * @param int $id_topic origin topic id
  861. * @param int $id_board board id
  862. * @param bool $next = true whether to increase or decrease the pointer
  863. * @param int $id_member = 0 member id
  864. * @param bool $includeUnapproved = false whether to include unapproved topics
  865. * @param bool $includeStickies = true whether to include sticky topics
  866. */
  867. function topicPointer($id_topic, $id_board, $next = true, $id_member = 0, $includeUnapproved = false, $includeStickies = true)
  868. {
  869. global $smcFunc;
  870. $request = $smcFunc['db_query']('', '
  871. SELECT t2.id_topic
  872. FROM {db_prefix}topics AS t
  873. INNER JOIN {db_prefix}topics AS t2 ON (' .
  874. (empty($includeStickies) ? '
  875. t2.id_last_msg {raw:strictly} t.id_last_msg' : '
  876. (t2.id_last_msg {raw:strictly} t.id_last_msg AND t2.is_sticky {raw:strictly_equal} t.is_sticky) OR t2.is_sticky {raw:strictly} t.is_sticky')
  877. . ')
  878. WHERE t.id_topic = {int:current_topic}
  879. AND t2.id_board = {int:current_board}' .
  880. ($includeUnapproved ? '' : '
  881. AND (t2.approved = {int:is_approved} OR (t2.id_member_started != {int:id_member_started} AND t2.id_member_started = {int:current_member}))'
  882. ) . '
  883. ORDER BY' . (
  884. $includeStickies ? '
  885. t2.is_sticky {raw:sorting},' :
  886. '') .
  887. ' t2.id_last_msg {raw:sorting}
  888. LIMIT 1',
  889. array(
  890. 'strictly' => $next ? '<' : '>',
  891. 'strictly_equal' => $next ? '<=' : '=>',
  892. 'sorting' => $next ? 'DESC' : '',
  893. 'current_board' => $id_board,
  894. 'current_member' => $id_member,
  895. 'current_topic' => $id_topic,
  896. 'is_approved' => 1,
  897. 'id_member_started' => 0,
  898. )
  899. );
  900. // Was there any?
  901. if ($smcFunc['db_num_rows']($request) == 0)
  902. {
  903. $smcFunc['db_free_result']($request);
  904. // Roll over - if we're going prev, get the last - otherwise the first.
  905. $request = $smcFunc['db_query']('', '
  906. SELECT id_topic
  907. FROM {db_prefix}topics
  908. WHERE id_board = {int:current_board}' .
  909. ($includeUnapproved ? '' : '
  910. AND (approved = {int:is_approved} OR (id_member_started != {int:id_member_started} AND id_member_started = {int:current_member}))') . '
  911. ORDER BY' . (
  912. $includeStickies ? ' is_sticky {raw:sorting},' :
  913. '').
  914. ' id_last_msg {raw:sorting}
  915. LIMIT 1',
  916. array(
  917. 'sorting' => $next ? 'DESC' : '',
  918. 'current_board' => $id_board,
  919. 'current_member' => $id_member,
  920. 'is_approved' => 1,
  921. 'id_member_started' => 0,
  922. )
  923. );
  924. }
  925. // Now you can be sure $topic is the id_topic to view.
  926. list ($topic) = $smcFunc['db_fetch_row']($request);
  927. $smcFunc['db_free_result']($request);
  928. return $topic;
  929. }
  930. /**
  931. * Set off/on unread reply subscription for a topic
  932. *
  933. * @param int $id_member
  934. * @param int $topic
  935. * @param bool $on = false
  936. */
  937. function setTopicRegard($id_member, $topic, $on = false)
  938. {
  939. global $smcFunc, $user_info;
  940. // find the current entry if it exists that is
  941. $request = $smcFunc['db_query']('', '
  942. SELECT id_msg
  943. FROM {db_prefix}log_topics
  944. WHERE id_member = {int:current_user}
  945. AND id_topic = {int:current_topic}',
  946. array(
  947. 'current_user' => $user_info['id'],
  948. 'current_topic' => $topic,
  949. )
  950. );
  951. list($was_set) = $smcFunc['db_fetch_row']($request);
  952. $smcFunc['db_free_result']($request);
  953. // Set topic disregard on/off for this topic.
  954. $smcFunc['db_insert'](empty($was_set) ? 'ignore' : 'replace',
  955. '{db_prefix}log_topics',
  956. array('id_member' => 'int', 'id_topic' => 'int', 'id_msg' => 'int', 'disregarded' => 'int'),
  957. array($id_member, $topic, $was_set ? $was_set : 0, $on ? 1 : 0),
  958. array('id_member', 'id_topic')
  959. );
  960. }
  961. /**
  962. * Get all the details for a given topic
  963. * - returns the basic topic information when $full is false
  964. * - returns topic details, subject, last message read, etc when full is true
  965. * - uses any integration information (value selects, tables and parameters) if passed and full is true
  966. *
  967. * @param array $topic_parameters can also accept a int value for a topic
  968. * @param bool $full
  969. * @param array $topic_selects (optional from integation)
  970. * @param array $topic_tables (optional from integation)
  971. */
  972. function getTopicInfo($topic_parameters, $full = false, $topic_selects = array(), $topic_tables = array())
  973. {
  974. global $smcFunc, $user_info, $modSettings, $board;
  975. // Nothing to do
  976. if (empty($topic_parameters))
  977. return false;
  978. // Build what we can with what we were given
  979. if (!is_array($topic_parameters))
  980. $topic_parameters = array(
  981. 'current_topic' => (int) $topic_parameters,
  982. 'current_member' => $user_info['id'],
  983. 'current_board' => (int) $board,
  984. );
  985. // Create the query, taking full and integration in to account
  986. $request = $smcFunc['db_query']('', '
  987. SELECT
  988. t.is_sticky, t.id_board, t.id_first_msg, t.id_last_msg, t.id_member_started, t.id_member_updated, t.id_poll,
  989. t.num_replies, t.num_views, t.locked, t.redirect_expires,
  990. t.id_redirect_topic, t.unapproved_posts, t.approved' . ($full ? ', ms.subject,
  991. ' . ($user_info['is_guest'] ? 't.id_last_msg + 1' : 'IFNULL(lt.id_msg, IFNULL(lmr.id_msg, -1)) + 1') . ' AS new_from
  992. ' . (!empty($modSettings['recycle_board']) && $modSettings['recycle_board'] == $board ? ', t.id_previous_board, t.id_previous_topic' : '') . '
  993. ' . (!empty($topic_selects) ? implode(',', $topic_selects) : '') . '
  994. ' . (!$user_info['is_guest'] ? ', IFNULL(lt.disregarded, 0) as disregarded' : '') : '') . '
  995. FROM {db_prefix}topics AS t' . ($full ? '
  996. INNER JOIN {db_prefix}messages AS ms ON (ms.id_msg = t.id_first_msg)' : '') . ($full && !$user_info['is_guest'] ? '
  997. LEFT JOIN {db_prefix}log_topics AS lt ON (lt.id_topic = {int:current_topic} AND lt.id_member = {int:current_member})
  998. LEFT JOIN {db_prefix}log_mark_read AS lmr ON (lmr.id_board = {int:current_board} AND lmr.id_member = {int:current_member})' : '') .
  999. (!empty($topic_tables) ? implode("\n\t", $topic_tables) : '') . '
  1000. WHERE t.id_topic = {int:current_topic}
  1001. LIMIT 1',
  1002. $topic_parameters
  1003. );
  1004. $topic_info = array();
  1005. if ($request !== false)
  1006. $topic_info = $smcFunc['db_fetch_assoc']($request);
  1007. $smcFunc['db_free_result']($request);
  1008. return $topic_info;
  1009. }
  1010. /**
  1011. * So long as you are sure... all old posts will be gone.
  1012. * Used in ManageMaintenance.php to prune old topics.
  1013. */
  1014. function removeOldTopics()
  1015. {
  1016. global $modSettings, $smcFunc;
  1017. isAllowedTo('admin_forum');
  1018. checkSession('post', 'admin');
  1019. // No boards at all? Forget it then :/.
  1020. if (empty($_POST['boards']))
  1021. redirectexit('action=admin;area=maintain;sa=topics');
  1022. // This should exist, but we can make sure.
  1023. $_POST['delete_type'] = isset($_POST['delete_type']) ? $_POST['delete_type'] : 'nothing';
  1024. // Custom conditions.
  1025. $condition = '';
  1026. $condition_params = array(
  1027. 'boards' => array_keys($_POST['boards']),
  1028. 'poster_time' => time() - 3600 * 24 * $_POST['maxdays'],
  1029. );
  1030. // Just moved notice topics?
  1031. if ($_POST['delete_type'] == 'moved')
  1032. {
  1033. $condition .= '
  1034. AND m.icon = {string:icon}
  1035. AND t.locked = {int:locked}';
  1036. $condition_params['icon'] = 'moved';
  1037. $condition_params['locked'] = 1;
  1038. }
  1039. // Otherwise, maybe locked topics only?
  1040. elseif ($_POST['delete_type'] == 'locked')
  1041. {
  1042. $condition .= '
  1043. AND t.locked = {int:locked}';
  1044. $condition_params['locked'] = 1;
  1045. }
  1046. // Exclude stickies?
  1047. if (isset($_POST['delete_old_not_sticky']))
  1048. {
  1049. $condition .= '
  1050. AND t.is_sticky = {int:is_sticky}';
  1051. $condition_params['is_sticky'] = 0;
  1052. }
  1053. // All we're gonna do here is grab the id_topic's and send them to removeTopics().
  1054. $request = $smcFunc['db_query']('', '
  1055. SELECT t.id_topic
  1056. FROM {db_prefix}topics AS t
  1057. INNER JOIN {db_prefix}messages AS m ON (m.id_msg = t.id_last_msg)
  1058. WHERE
  1059. m.poster_time < {int:poster_time}' . $condition . '
  1060. AND t.id_board IN ({array_int:boards})',
  1061. $condition_params
  1062. );
  1063. $topics = array();
  1064. while ($row = $smcFunc['db_fetch_assoc']($request))
  1065. $topics[] = $row['id_topic'];
  1066. $smcFunc['db_free_result']($request);
  1067. removeTopics($topics, false, true);
  1068. // Log an action into the moderation log.
  1069. logAction('pruned', array('days' => $_POST['maxdays']));
  1070. redirectexit('action=admin;area=maintain;sa=topics;done=purgeold');
  1071. }
  1072. /**
  1073. * Retrieve all topics started by the given member.
  1074. *
  1075. * @param int $memberID
  1076. */
  1077. function topicsStartedBy($memberID)
  1078. {
  1079. global $smcFunc;
  1080. // Fetch all topics started by this user.
  1081. $request = $smcFunc['db_query']('', '
  1082. SELECT t.id_topic
  1083. FROM {db_prefix}topics AS t
  1084. WHERE t.id_member_started = {int:selected_member}',
  1085. array(
  1086. 'selected_member' => $memberID,
  1087. )
  1088. );
  1089. $topicIDs = array();
  1090. while ($row = $smcFunc['db_fetch_assoc']($request))
  1091. $topicIDs[] = $row['id_topic'];
  1092. $smcFunc['db_free_result']($request);
  1093. return $topicIDs;
  1094. }
  1095. /**
  1096. * Retrieve the messages of the given topic, that are at or after
  1097. * a message.
  1098. * Used by split topics actions.
  1099. */
  1100. function messagesAfter($topic, $message)
  1101. {
  1102. global $smcFunc;
  1103. // Fetch the message IDs of the topic that are at or after the message.
  1104. $request = $smcFunc['db_query']('', '
  1105. SELECT id_msg
  1106. FROM {db_prefix}messages
  1107. WHERE id_topic = {int:current_topic}
  1108. AND id_msg >= {int:split_at}',
  1109. array(
  1110. 'current_topic' => $topic,
  1111. 'split_at' => $message,
  1112. )
  1113. );
  1114. while ($row = $smcFunc['db_fetch_assoc']($request))
  1115. $messages[] = $row['id_msg'];
  1116. $smcFunc['db_free_result']($request);
  1117. return $messages;
  1118. }
  1119. /**
  1120. * Retrieve a few data on a particular message.
  1121. *
  1122. * @param int $topic
  1123. * @param int $message
  1124. */
  1125. function messageInfo($topic, $message)
  1126. {
  1127. global $smcFunc, $modSettings;
  1128. // @todo isn't this a duplicate?
  1129. // Retrieve a few info on the specific message.
  1130. $request = $smcFunc['db_query']('', '
  1131. SELECT m.subject, t.num_replies, t.unapproved_posts, t.id_first_msg, t.approved
  1132. FROM {db_prefix}messages AS m
  1133. INNER JOIN {db_prefix}topics AS t ON (t.id_topic = {int:current_topic})
  1134. WHERE m.id_msg = {int:split_at}' . (!$modSettings['postmod_active'] || allowedTo('approve_posts') ? '' : '
  1135. AND m.approved = 1') . '
  1136. AND m.id_topic = {int:current_topic}
  1137. LIMIT 1',
  1138. array(
  1139. 'current_topic' => $topic,
  1140. 'split_at' => $message,
  1141. )
  1142. );
  1143. if ($smcFunc['db_num_rows']($request) == 0)
  1144. fatal_lang_error('cant_find_messages');
  1145. list ($subject, $num_replies, $unapproved_posts, $id_first_msg, $approved) = $smcFunc['db_fetch_row']($request);
  1146. $smcFunc['db_free_result']($request);
  1147. $messageInfo = array(
  1148. 'subject' => $subject,
  1149. 'num_replies' => $num_replies,
  1150. 'unapproved_posts' => $unapproved_posts,
  1151. 'id_first_msg' => $id_first_msg,
  1152. 'approved' => $approved
  1153. );
  1154. return $messageInfo;
  1155. }
  1156. /**
  1157. * Select a part of the messages in a topic.
  1158. *
  1159. * @param int $topic
  1160. * @param int $start
  1161. * @param int $per_page
  1162. * @param bool $only_approved
  1163. */
  1164. function selectMessages($topic, $start, $per_page, $excluded_messages = array(), $only_approved = false)
  1165. {
  1166. global $smcFunc, $modSettings;
  1167. // Get the messages and stick them into an array.
  1168. $request = $smcFunc['db_query']('', '
  1169. SELECT m.subject, IFNULL(mem.real_name, m.poster_name) AS real_name, m.poster_time, m.body, m.id_msg, m.smileys_enabled
  1170. FROM {db_prefix}messages AS m
  1171. LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = m.id_member)
  1172. WHERE m.id_topic = {int:current_topic}' . (empty($excluded_messages) ? '' : '
  1173. AND id_msg NOT IN ({array_int:no_split_msgs})') . (!$only_approved ? '' : '
  1174. AND approved = {int:is_approved}') . '
  1175. ORDER BY m.id_msg DESC
  1176. LIMIT {int:start}, {int:messages_per_page}',
  1177. array(
  1178. 'current_topic' => $topic,
  1179. 'no_split_msgs' => !empty($excluded_messages) ? $excluded_messages : array(),
  1180. 'is_approved' => 1,
  1181. 'start' => $start,
  1182. 'messages_per_page' => $per_page,
  1183. )
  1184. );
  1185. $messages = array();
  1186. for ($counter = 0; $row = $smcFunc['db_fetch_assoc']($request); $counter ++)
  1187. {
  1188. censorText($row['subject']);
  1189. censorText($row['body']);
  1190. $row['body'] = parse_bbc($row['body'], $row['smileys_enabled'], $row['id_msg']);
  1191. $messages[$row['id_msg']] = array(
  1192. 'id' => $row['id_msg'],
  1193. 'alternate' => $counter % 2,
  1194. 'subject' => $row['subject'],
  1195. 'time' => timeformat($row['poster_time']),
  1196. 'timestamp' => forum_time(true, $row['poster_time']),
  1197. 'body' => $row['body'],
  1198. 'poster' => $row['real_name'],
  1199. );
  1200. }
  1201. $smcFunc['db_free_result']($request);
  1202. return $messages;
  1203. }
  1204. /**
  1205. * Retrieve unapproved posts of the member
  1206. * in a specific topic
  1207. *
  1208. * @param int $id_topic topic id
  1209. * @param int $id_member member id
  1210. */
  1211. function unapprovedPosts($id_topic, $id_member)
  1212. {
  1213. global $smcFunc;
  1214. // not all guests are the same!
  1215. if (empty($id_member))
  1216. return array();
  1217. $request = $smcFunc['db_query']('', '
  1218. SELECT COUNT(id_member) AS my_unapproved_posts
  1219. FROM {db_prefix}messages
  1220. WHERE id_topic = {int:current_topic}
  1221. AND id_member = {int:current_member}
  1222. AND approved = 0',
  1223. array(
  1224. 'current_topic' => $id_topic,
  1225. 'current_member' => $id_member,
  1226. )
  1227. );
  1228. list ($myUnapprovedPosts) = $smcFunc['db_fetch_row']($request);
  1229. $smcFunc['db_free_result']($request);
  1230. return $myUnapprovedPosts;
  1231. }