Subs-ReportedPosts.php 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529
  1. <?php
  2. /**
  3. * Perform CRUD actions for reported posts and moderation comments.
  4. *
  5. * Simple Machines Forum (SMF)
  6. *
  7. * @package SMF
  8. * @author Simple Machines http://www.simplemachines.org
  9. * @copyright 2014 Simple Machines and individual contributors
  10. * @license http://www.simplemachines.org/about/smf/license.php BSD
  11. *
  12. * @version 2.1 Alpha 1
  13. */
  14. if (!defined('SMF'))
  15. die('No direct access...');
  16. /**
  17. * Updates a report with the given parameters. Logs each action via logAction()
  18. *
  19. * @param string $action The action to perform. Accepts "closed" and "ignore".
  20. * @param integer $value The new value to update.
  21. * @params integer|array $report_id The affected report(s).
  22. */
  23. function updateReport($action, $value, $report_id)
  24. {
  25. global $smcFunc, $user_info, $context;
  26. // Don't bother.
  27. if (empty($action) || empty($report_id))
  28. return false;
  29. // Add the "_all" thingy.
  30. if ($action == 'ignore')
  31. $action = 'ignore_all';
  32. // Update the report...
  33. $smcFunc['db_query']('', '
  34. UPDATE {db_prefix}log_reported
  35. SET {raw:action} = {string:value}
  36. '. (is_array($report_id) ? 'WHERE id_report IN ({array_int:id_report})' : 'WHERE id_report = {int:id_report}') .'
  37. AND ' . $user_info['mod_cache']['bq'],
  38. array(
  39. 'action' => $action,
  40. 'value' => $value,
  41. 'id_report' => $report_id,
  42. )
  43. );
  44. // From now on, lets work with arrays, makes life easier.
  45. $report_id = (array) $report_id;
  46. // Get the board, topic and message for this report
  47. $request = $smcFunc['db_query']('', '
  48. SELECT id_board, id_topic, id_msg, id_report
  49. FROM {db_prefix}log_reported
  50. WHERE id_report IN ({array_int:id_report})',
  51. array(
  52. 'id_report' => $report_id,
  53. )
  54. );
  55. // Set up the data for the log...
  56. $extra = array();
  57. while ($row = $smcFunc['db_fetch_assoc']($request))
  58. $extra[$row['id_report']] = array(
  59. 'report' => $row['id_report'],
  60. 'board' => $row['id_board'],
  61. 'message' => $row['id_msg'],
  62. 'topic' => $row['id_topic'],
  63. );
  64. $smcFunc['db_free_result']($request);
  65. // Back to "ignore".
  66. if ($action == 'ignore_all')
  67. $action = 'ignore';
  68. $log_report = $action == 'ignore' ? (!empty($value) ? 'ignore' : 'unignore') : (!empty($value) ? 'close' : 'open');
  69. // Log this action.
  70. if (!empty($extra))
  71. foreach ($extra as $report)
  72. logAction($log_report . '_report', $report);
  73. // Time to update.
  74. updateSettings(array('last_mod_report_action' => time()));
  75. recountOpenReports();
  76. }
  77. /**
  78. * Counts how many reports are in total. Used for creating pagination.
  79. *
  80. * @param int $closed 1 for counting closed reports, 0 for open ones.
  81. * @return integer How many reports.
  82. */
  83. function countReports($closed = 0)
  84. {
  85. global $smcFunc, $user_info;
  86. $total_reports = 0;
  87. // How many entries are we viewing?
  88. $request = $smcFunc['db_query']('', '
  89. SELECT COUNT(*)
  90. FROM {db_prefix}log_reported AS lr
  91. WHERE lr.closed = {int:view_closed}
  92. AND ' . ($user_info['mod_cache']['bq'] == '1=1' || $user_info['mod_cache']['bq'] == '0=1' ? $user_info['mod_cache']['bq'] : 'lr.' . $user_info['mod_cache']['bq']),
  93. array(
  94. 'view_closed' => (int) $closed,
  95. )
  96. );
  97. list ($total_reports) = $smcFunc['db_fetch_row']($request);
  98. $smcFunc['db_free_result']($request);
  99. return $total_reports;
  100. }
  101. /**
  102. * Get all possible reports the current user can see.
  103. *
  104. * @param int $closed 1 for closed reports, 0 for open ones.
  105. * @return array the reports data with the report ID as key.
  106. */
  107. function getReports($closed = 0)
  108. {
  109. global $smcFunc, $context, $user_info, $scripturl;
  110. // Lonely, standalone var.
  111. $reports = array();
  112. // By George, that means we in a position to get the reports, golly good.
  113. $request = $smcFunc['db_query']('', '
  114. SELECT lr.id_report, lr.id_msg, lr.id_topic, lr.id_board, lr.id_member, lr.subject, lr.body,
  115. lr.time_started, lr.time_updated, lr.num_reports, lr.closed, lr.ignore_all,
  116. IFNULL(mem.real_name, lr.membername) AS author_name, IFNULL(mem.id_member, 0) AS id_author
  117. FROM {db_prefix}log_reported AS lr
  118. LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = lr.id_member)
  119. WHERE lr.closed = {int:view_closed}
  120. AND ' . ($user_info['mod_cache']['bq'] == '1=1' || $user_info['mod_cache']['bq'] == '0=1' ? $user_info['mod_cache']['bq'] : 'lr.' . $user_info['mod_cache']['bq']) . '
  121. ORDER BY lr.time_updated DESC
  122. LIMIT ' . $context['start'] . ', 10',
  123. array(
  124. 'view_closed' => (int) $closed,
  125. )
  126. );
  127. $report_ids = array();
  128. $report_boards_ids = array();
  129. for ($i = 0; $row = $smcFunc['db_fetch_assoc']($request); $i++)
  130. {
  131. $report_ids[] = $row['id_report'];
  132. $report_boards_ids[] = $row['id_board'];
  133. $reports[$row['id_report']] = array(
  134. 'id' => $row['id_report'],
  135. 'alternate' => $i % 2,
  136. 'topic' => array(
  137. 'id' => $row['id_topic'],
  138. 'id_msg' => $row['id_msg'],
  139. 'id_board' => $row['id_board'],
  140. 'href' => $scripturl . '?topic=' . $row['id_topic'] . '.msg' . $row['id_msg'] . '#msg' . $row['id_msg'],
  141. ),
  142. 'report_href' => $scripturl . '?action=moderate;area=reports;sa=details;rid=' . $row['id_report'],
  143. 'author' => array(
  144. 'id' => $row['id_author'],
  145. 'name' => $row['author_name'],
  146. 'link' => $row['id_author'] ? '<a href="' . $scripturl . '?action=profile;u=' . $row['id_author'] . '">' . $row['author_name'] . '</a>' : $row['author_name'],
  147. 'href' => $scripturl . '?action=profile;u=' . $row['id_author'],
  148. ),
  149. 'comments' => array(),
  150. 'time_started' => timeformat($row['time_started']),
  151. 'last_updated' => timeformat($row['time_updated']),
  152. 'subject' => $row['subject'],
  153. 'body' => parse_bbc($row['body']),
  154. 'num_reports' => $row['num_reports'],
  155. 'closed' => $row['closed'],
  156. 'ignore' => $row['ignore_all']
  157. );
  158. }
  159. $smcFunc['db_free_result']($request);
  160. // Get the names of boards those topics are in. Slightly faster this way.
  161. if (!empty($report_boards_ids))
  162. {
  163. $report_boards_ids = array_unique($report_boards_ids);
  164. $board_names = array();
  165. $request = $smcFunc['db_query']('', '
  166. SELECT id_board, name
  167. FROM {db_prefix}boards
  168. WHERE id_board IN ({array_int:boards})',
  169. array(
  170. 'boards' => $report_boards_ids,
  171. )
  172. );
  173. while ($row = $smcFunc['db_fetch_assoc']($request))
  174. $board_names[$row['id_board']] = $row['name'];
  175. $smcFunc['db_free_result']($request);
  176. foreach ($reports as $id_report => $report)
  177. if (!empty($board_names[$report['topic']['id_board']]))
  178. $reports[$id_report]['topic']['board_name'] = $board_names[$report['topic']['id_board']];
  179. }
  180. // Now get all the people who reported it.
  181. if (!empty($report_ids))
  182. {
  183. $request = $smcFunc['db_query']('', '
  184. SELECT lrc.id_comment, lrc.id_report, lrc.time_sent, lrc.comment,
  185. IFNULL(mem.id_member, 0) AS id_member, IFNULL(mem.real_name, lrc.membername) AS reporter
  186. FROM {db_prefix}log_reported_comments AS lrc
  187. LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = lrc.id_member)
  188. WHERE lrc.id_report IN ({array_int:report_list})',
  189. array(
  190. 'report_list' => $report_ids,
  191. )
  192. );
  193. while ($row = $smcFunc['db_fetch_assoc']($request))
  194. {
  195. $reports[$row['id_report']]['comments'][] = array(
  196. 'id' => $row['id_comment'],
  197. 'message' => $row['comment'],
  198. 'time' => timeformat($row['time_sent']),
  199. 'member' => array(
  200. 'id' => $row['id_member'],
  201. 'name' => empty($row['reporter']) ? $txt['guest'] : $row['reporter'],
  202. 'link' => $row['id_member'] ? '<a href="' . $scripturl . '?action=profile;u=' . $row['id_member'] . '">' . $row['reporter'] . '</a>' : (empty($row['reporter']) ? $txt['guest'] : $row['reporter']),
  203. 'href' => $row['id_member'] ? $scripturl . '?action=profile;u=' . $row['id_member'] : '',
  204. ),
  205. );
  206. }
  207. $smcFunc['db_free_result']($request);
  208. }
  209. // Get the boards where the current user can remove any message.
  210. $context['report_remove_any_boards'] = $user_info['is_admin'] ? $report_boards_ids : array_intersect($report_boards_ids, boardsAllowedTo('remove_any'));
  211. $context['report_manage_bans'] = allowedTo('manage_bans');
  212. return $reports;
  213. }
  214. /**
  215. * Recount all open reports. Sets a SESSION var with the updated info.
  216. *
  217. * @return int the update open report count.
  218. */
  219. function recountOpenReports()
  220. {
  221. global $user_info, $smcFunc;
  222. $request = $smcFunc['db_query']('', '
  223. SELECT COUNT(*)
  224. FROM {db_prefix}log_reported
  225. WHERE ' . $user_info['mod_cache']['bq'] . '
  226. AND closed = {int:not_closed}
  227. AND ignore_all = {int:not_ignored}',
  228. array(
  229. 'not_closed' => 0,
  230. 'not_ignored' => 0,
  231. )
  232. );
  233. list ($open_reports) = $smcFunc['db_fetch_row']($request);
  234. $smcFunc['db_free_result']($request);
  235. $_SESSION['rc'] = array(
  236. 'id' => $user_info['id'],
  237. 'time' => time(),
  238. 'reports' => $open_reports,
  239. );
  240. return $open_reports;
  241. }
  242. /**
  243. * Gets additional information for a specific report.
  244. *
  245. * @param int $report_id The report ID to get the info from.
  246. * @return array|bool the report data. Boolean false if no report_id was provided.
  247. */
  248. function getReportDetails($report_id)
  249. {
  250. global $smcFunc, $user_info;
  251. if (empty($report_id))
  252. return false;
  253. // Get the report details, need this so we can limit access to a particular board.
  254. $request = $smcFunc['db_query']('', '
  255. SELECT lr.id_report, lr.id_msg, lr.id_topic, lr.id_board, lr.id_member, lr.subject, lr.body,
  256. lr.time_started, lr.time_updated, lr.num_reports, lr.closed, lr.ignore_all,
  257. IFNULL(mem.real_name, lr.membername) AS author_name, IFNULL(mem.id_member, 0) AS id_author
  258. FROM {db_prefix}log_reported AS lr
  259. LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = lr.id_member)
  260. WHERE lr.id_report = {int:id_report}
  261. AND ' . ($user_info['mod_cache']['bq'] == '1=1' || $user_info['mod_cache']['bq'] == '0=1' ? $user_info['mod_cache']['bq'] : 'lr.' . $user_info['mod_cache']['bq']) . '
  262. LIMIT 1',
  263. array(
  264. 'id_report' => $report_id,
  265. )
  266. );
  267. // So did we find anything?
  268. if (!$smcFunc['db_num_rows']($request))
  269. return false;
  270. // Woohoo we found a report and they can see it!
  271. $row = $smcFunc['db_fetch_assoc']($request);
  272. $smcFunc['db_free_result']($request);
  273. return $row;
  274. }
  275. /**
  276. * Gets both report comments as well as any moderator comment.
  277. *
  278. * @param int $report_id The report ID to get the info from.
  279. * @return array|bool an associative array with 2 keys comments and mod_comments. Boolean false if no report_id was provided.
  280. */
  281. function getReportComments($report_id)
  282. {
  283. global $smcFunc, $scripturl;
  284. if (empty($report_id))
  285. return false;
  286. $report = array(
  287. 'comments' => array(),
  288. 'mod_comments' => array()
  289. );
  290. // So what bad things do the reporters have to say about it?
  291. $request = $smcFunc['db_query']('', '
  292. SELECT lrc.id_comment, lrc.id_report, lrc.time_sent, lrc.comment, lrc.member_ip,
  293. IFNULL(mem.id_member, 0) AS id_member, IFNULL(mem.real_name, lrc.membername) AS reporter
  294. FROM {db_prefix}log_reported_comments AS lrc
  295. LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = lrc.id_member)
  296. WHERE lrc.id_report = {int:id_report}',
  297. array(
  298. 'id_report' => $report_id,
  299. )
  300. );
  301. while ($row = $smcFunc['db_fetch_assoc']($request))
  302. {
  303. $report['comments'][] = array(
  304. 'id' => $row['id_comment'],
  305. 'message' => strtr($row['comment'], array("\n" => '<br>')),
  306. 'time' => timeformat($row['time_sent']),
  307. 'member' => array(
  308. 'id' => $row['id_member'],
  309. 'name' => empty($row['reporter']) ? $txt['guest'] : $row['reporter'],
  310. 'link' => $row['id_member'] ? '<a href="' . $scripturl . '?action=profile;u=' . $row['id_member'] . '">' . $row['reporter'] . '</a>' : (empty($row['reporter']) ? $txt['guest'] : $row['reporter']),
  311. 'href' => $row['id_member'] ? $scripturl . '?action=profile;u=' . $row['id_member'] : '',
  312. 'ip' => !empty($row['member_ip']) && allowedTo('moderate_forum') ? '<a href="' . $scripturl . '?action=trackip;searchip=' . $row['member_ip'] . '">' . $row['member_ip'] . '</a>' : '',
  313. ),
  314. );
  315. }
  316. $smcFunc['db_free_result']($request);
  317. // Hang about old chap, any comments from moderators on this one?
  318. $request = $smcFunc['db_query']('', '
  319. SELECT lc.id_comment, lc.id_notice, lc.log_time, lc.body,
  320. IFNULL(mem.id_member, 0) AS id_member, IFNULL(mem.real_name, lc.member_name) AS moderator
  321. FROM {db_prefix}log_comments AS lc
  322. LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = lc.id_member)
  323. WHERE lc.id_notice = {int:id_report}
  324. AND lc.comment_type = {literal:reportc}',
  325. array(
  326. 'id_report' => $report_id,
  327. )
  328. );
  329. while ($row = $smcFunc['db_fetch_assoc']($request))
  330. {
  331. $report['mod_comments'][] = array(
  332. 'id' => $row['id_comment'],
  333. 'message' => parse_bbc($row['body']),
  334. 'time' => timeformat($row['log_time']),
  335. 'can_edit' => allowedTo('admin_forum') || (($user_info['id'] == $row['id_member']) && allowedTo('moderate_forum')),
  336. 'member' => array(
  337. 'id' => $row['id_member'],
  338. 'name' => $row['moderator'],
  339. 'link' => $row['id_member'] ? '<a href="' . $scripturl . '?action=profile;u=' . $row['id_member'] . '">' . $row['moderator'] . '</a>' : $row['moderator'],
  340. 'href' => $scripturl . '?action=profile;u=' . $row['id_member'],
  341. ),
  342. );
  343. }
  344. $smcFunc['db_free_result']($request);
  345. return $report;
  346. }
  347. /**
  348. * Gets specific details about a moderator comment. It also adds a permission for editing/deleting the comment,
  349. * by default only admins and the author of the comment can edit/delete it.
  350. *
  351. * @param int $comment_id The moderator comment ID to get the info from.
  352. * @return array|bool an array with the fetched data. Boolean false if no report_id was provided.
  353. */
  354. function getCommentModDetails($comment_id)
  355. {
  356. global $smcFunc, $user_info;
  357. $comment = array();
  358. if (empty($comment_id))
  359. return false;
  360. $request = $smcFunc['db_query']('', '
  361. SELECT id_comment, id_notice, log_time, body, id_member
  362. FROM {db_prefix}log_comments
  363. WHERE id_comment = {int:id_comment}
  364. AND comment_type = {literal:reportc}',
  365. array(
  366. 'id_comment' => $comment_id,
  367. )
  368. );
  369. $comment = $smcFunc['db_fetch_assoc']($request);
  370. $smcFunc['db_free_result']($request);
  371. // Add the permission
  372. if (!empty($comment))
  373. $comment['can_edit'] = allowedTo('admin_forum') || (($user_info['id'] == $comment['id_member']) && allowedTo('moderate_forum'));
  374. return $comment;
  375. }
  376. /**
  377. * Inserts a new moderator comment to the DB.
  378. *
  379. * @param int $report_id The report ID is used to fire a notification about the event.
  380. * @param array $data a formatted array of data to be inserted. Should be already properly sanitized.
  381. * @return bool Boolean false if no data was provided.
  382. */
  383. function saveModComment($report_id, $data)
  384. {
  385. global $smcFunc, $user_info;
  386. if (empty($data))
  387. return false;
  388. $data = array_merge(array($user_info['id'], $user_info['name'], 'reportc', ''), $data);
  389. $smcFunc['db_insert']('',
  390. '{db_prefix}log_comments',
  391. array(
  392. 'id_member' => 'int', 'member_name' => 'string', 'comment_type' => 'string', 'recipient_name' => 'string',
  393. 'id_notice' => 'int', 'body' => 'string', 'log_time' => 'int',
  394. ),
  395. $data,
  396. array('id_comment')
  397. );
  398. $last_comment = $smcFunc['db_insert_id']('{db_prefix}log_comments', 'id_comment');
  399. $report = getReportDetails($report_id);
  400. // And get ready to notify people.
  401. if (!empty($report))
  402. $smcFunc['db_insert']('insert',
  403. '{db_prefix}background_tasks',
  404. array('task_file' => 'string', 'task_class' => 'string', 'task_data' => 'string', 'claimed_time' => 'int'),
  405. array('$sourcedir/tasks/MsgReportReply-Notify.php', 'MsgReportReply_Notify_Background', serialize(array(
  406. 'report_id' => $report_id,
  407. 'comment_id' => $last_comment,
  408. 'msg_id' => $report['id_msg'],
  409. 'topic_id' => $report['id_topic'],
  410. 'board_id' => $report['id_board'],
  411. 'sender_id' => $user_info['id'],
  412. 'sender_name' => $user_info['name'],
  413. 'time' => time(),
  414. )), 0),
  415. array('id_task')
  416. );
  417. }
  418. /**
  419. * Saves the new information whenever a moderator comment is edited.
  420. *
  421. * @param int $comment_id The edited moderator comment ID.
  422. * @param array $data The new data to de inserted. Should be already properly sanitized.
  423. * @return bool Boolean false if no data or no comment ID was provided.
  424. */
  425. function editModComment($comment_id, $edited_comment)
  426. {
  427. global $smcFunc;
  428. if (empty($comment_id) || empty($edited_comment))
  429. return false;
  430. $smcFunc['db_query']('', '
  431. UPDATE {db_prefix}log_comments
  432. SET body = {string:body}
  433. WHERE id_comment = {int:id_comment}',
  434. array(
  435. 'body' => $edited_comment,
  436. 'id_comment' => $comment_id,
  437. )
  438. );
  439. }
  440. /**
  441. * Deletes a moderator comment from the DB.
  442. *
  443. * @param int $comment_id The moderator comment ID used to identify which report will be deleted.
  444. * @return bool Boolean false if no data was provided.
  445. */
  446. function deleteModComment($comment_id)
  447. {
  448. global $smcFunc;
  449. if (empty($comment_id))
  450. return false;
  451. $smcFunc['db_query']('', '
  452. DELETE FROM {db_prefix}log_comments
  453. WHERE id_comment = {int:comment_id}',
  454. array(
  455. 'comment_id' => $comment_id,
  456. )
  457. );
  458. }
  459. ?>