From 9c5ec12aaadee6aaf7ed24f2dcec98b6ed0cf50d Mon Sep 17 00:00:00 2001 From: unknown <8n-tech@users.noreply.github.com> Date: Tue, 21 Oct 2014 07:50:25 -0500 Subject: [PATCH] [#184] Reports made to clean posts are now ignored correctly (and in accordance with the local/global duality). Marking posts clean dismisses posts (also in accordance with local/global duality). Fixed up some templating issues (now display more correct messages and omit actions that are invalid). Moved Clean action off post-level and into reports action. --- inc/display.php | 29 ++++------- inc/mod/pages.php | 81 ++++++++++++++++++++++++++----- mod.php | 20 ++++---- post.php | 65 +++++++++++++++++-------- stylesheets/style.css | 4 +- templates/mod/report.html | 8 ++- templates/mod/report_content.html | 14 ++++-- 7 files changed, 151 insertions(+), 70 deletions(-) diff --git a/inc/display.php b/inc/display.php index bb6120ee..9b4c2d83 100644 --- a/inc/display.php +++ b/inc/display.php @@ -343,6 +343,7 @@ function embed_html($link) { return 'Embedding error.'; } + class Post { public function __construct($post, $root=null, $mod=false) { global $config; @@ -410,7 +411,14 @@ class Post { $query->execute() or error(db_error($query)); if( !($this->clean = $query->fetch(PDO::FETCH_ASSOC)) ) { - $this->clean = array(); + $this->clean = array( + 'post_id' => $this->id, + 'board_id' => $board['uri'], + 'clean_local' => "0", + 'clean_global' => "0", + 'clean_local_mod_id' => null, + 'clean_global_mod_id' => null, + ); } } @@ -418,7 +426,7 @@ class Post { } }; -class Thread { +class Thread extends Post { public function __construct($post, $root = null, $mod = false, $hr = true) { global $config; if (!isset($root)) @@ -491,22 +499,5 @@ class Thread { return $built; } - public function getClean( ) { - global $board, $config, $debug; - - if( !isset( $this->clean ) ) { - $query = prepare("SELECT * FROM `post_clean` WHERE `post_id` = :post AND `board_id` = :board"); - $query->bindValue( ':board', $board['uri'] ); - $query->bindValue( ':post', $this->id ); - - $query->execute() or error(db_error($query)); - - if( !($this->clean = $query->fetch(PDO::FETCH_ASSOC)) ) { - $this->clean = array(); - } - } - - return $this->clean; - } }; diff --git a/inc/mod/pages.php b/inc/mod/pages.php index dde0c1bc..37b3892e 100644 --- a/inc/mod/pages.php +++ b/inc/mod/pages.php @@ -1614,7 +1614,7 @@ function mod_edit_post($board, $edit_raw_html, $postID) { } buildIndex(); - + rebuildThemes('post', $board); header('Location: ?/' . sprintf($config['board_path'], $board) . $config['dir']['res'] . sprintf($config['file_page'], $post['thread'] ? $post['thread'] : $postID) . '#' . $postID, true, $config['redirect_http']); @@ -2384,6 +2384,11 @@ function mod_reports() { $po = new Post($content, '?/', $mod); } + // Fetch clean status. + $po->getClean(); + $clean = $po->clean; + + // Add each report's template to this container. $report_html = ""; $reports_can_demote = false; @@ -2396,6 +2401,7 @@ function mod_reports() { 'config' => $config, 'mod' => $mod, 'global' => $global, + 'clean' => $clean, 'uri_dismiss' => "?/{$uri_report_base}/dismiss", 'uri_ip' => "?/{$uri_report_base}/dismissall", @@ -2430,8 +2436,14 @@ function mod_reports() { $content_reports ); - $uri_content_base = "reports/" . ($global ? "global/" : "" ) . "content/"; - $uri_clean_base = "{$report_item['board_id']}/clean/{$content['id']}"; + + // Figure out some stuff we need for the page. + $reports_can_demote = ( $clean['clean_local'] ? false : $reports_can_demote ); + $reports_can_promote = ( $clean['clean_global'] ? false : $reports_can_promote ); + $uri_content_base = "reports/" . ($global ? "global/" : "" ) . "content/"; + $uri_clean_base = "reports/" . ($global ? "global/" : "" ) . "{$report_item['board_id']}/clean/{$content['id']}"; + + // Build the actions page. $content_html = Element('mod/report_content.html', array( 'reports_html' => $report_html, 'reports_can_demote' => $reports_can_demote, @@ -2441,7 +2453,9 @@ function mod_reports() { 'content_html' => $po->build(true), 'content_board' => $report_item['board_id'], - 'content' => $content, + 'content' => (array) $content, + + 'clean' => $clean, 'uri_content_demote' => "?/{$uri_content_base}{$report_item['board_id']}/{$content['id']}/demote", 'uri_content_promote' => "?/{$uri_content_base}{$report_item['board_id']}/{$content['id']}/promote", @@ -2813,7 +2827,7 @@ function mod_recent_posts($lim) { } -function mod_clean( $board, $unclean, $post, $global, $local ) { +function mod_report_clean( $global_reports, $board, $unclean, $post, $global, $local ) { global $config, $mod; if( !openBoard($board) ) { @@ -2853,7 +2867,7 @@ function mod_clean( $board, $unclean, $post, $global, $local ) { $query->execute() or error(db_error($query)); // If the $clean object doesn't exist we need to insert a row for this post. - if( !($clean = $query->fetch(PDO::FETCH_ASSOC)) ) { + if( !($cleanRecord = $query->fetch(PDO::FETCH_ASSOC)) ) { $query = prepare("INSERT INTO `post_clean` (`post_id`, `board_id`) VALUES ( :post, :board )"); $query->bindValue( ':board', $board ); $query->bindValue( ':post', $post ); @@ -2864,7 +2878,7 @@ function mod_clean( $board, $unclean, $post, $global, $local ) { error("The database failed to create a record for this content in `post_clean` to record clean status."); } - $clean = true; + $cleanRecord = true; } } // Revoking clean status (open it to reports?) @@ -2876,13 +2890,13 @@ function mod_clean( $board, $unclean, $post, $global, $local ) { $query->execute() or error(db_error($query)); - if( !($clean = $query->fetch(PDO::FETCH_ASSOC)) ) { + if( !($cleanRecord = $query->fetch(PDO::FETCH_ASSOC)) ) { error($config['error']['404']); } } // Update the `post_clean` row represented by $clean. - if( $clean ) { + if( $cleanRecord ) { // Build our query based on the URI arguments. if( $global && $local ) { $query = prepare("UPDATE `post_clean` SET {$query_global}, {$query_global_mod}, {$query_local}, {$query_local_mod} WHERE `board_id` = :board AND `post_id` = :post"); @@ -2895,21 +2909,64 @@ function mod_clean( $board, $unclean, $post, $global, $local ) { } $query->bindValue( ':clean', !$unclean ); - $query->bindValue( ':mod', $mod['id'] ); + $query->bindValue( ':mod', $unclean ? NULL : $mod['id'] ); $query->bindValue( ':board', $board ); $query->bindValue( ':post', $post ); $query->execute() or error(db_error($query)); + // Finally, run a query to tidy up our records. + if( $unclean ) { + // Query is removing clean status from content. + // Remove any clean records that are now null. + $cleanup = prepare("DELETE FROM `post_clean` WHERE `clean_local` = FALSE AND `clean_global` = FALSE"); + $query->execute() or error(db_error($query)); + } + else { + // Content is clean, auto-handle all reports. + + // If this is a total clean, we don't need to update records first. + if( !($global && $local) ) { + $query = prepare("UPDATE `reports` SET `" . ($local ? "local" : "global") . "` = FALSE WHERE `board` = :board AND `post` = :post"); + $query->bindValue( ':board', $board ); + $query->bindValue( ':post', $post ); + + $query->execute() or error(db_error($query)); + + // If we didn't hit anything, this content doesn't have reports, so don't run the delete query. + $require_delete = ($query->rowCount() > 0); + + if( $require_delete ) { + $query = prepare("DELETE FROM `reports` WHERE `local` = FALSE and `global` = FALSE"); + + $query->execute() or error(db_error($query)); + } + } + // This is a total clean, so delete content by ID rather than via cleanup. + else { + $query = prepare("DELETE FROM `reports` WHERE `board` = :board AND `post` = :post"); + + $query->bindValue( ':board', $board ); + $query->bindValue( ':post', $post ); + + $query->execute() or error(db_error($query)); + } + } + // Log the action. - // This is super important because a mod intentionally screwing with clean status needs to be found out, fast. + // Having clear wording of ths log is very important because of the nature of clean status. $log_action = ($unclean ? "Closed" : "Re-opened" ); $log_scope = ($local && $global ? "local and global" : ($local ? "local" : "global" ) ); modLog( "{$log_action} reports for post #{$post} in {$log_scope}.", $board); } // Redirect - header('Location: ?/' . sprintf($config['board_path'], $board) . $config['file_index'], true, $config['redirect_http']); + if( $global_reports ) { + header('Location: ?/reports/global', true, $config['redirect_http']); + } + else { + header('Location: ?/reports', true, $config['redirect_http']); + } } function mod_config($board_config = false) { diff --git a/mod.php b/mod.php index 869d6af9..45c836ac 100644 --- a/mod.php +++ b/mod.php @@ -60,15 +60,16 @@ $pages = array( // and if the return address should also be the global dashboard. // Important to note that (?:global) will make no argument. // (global)? will make argument 0 either "global" or "". - '/reports(?:/)?' => 'reports', // report queue - '/reports/(global)?(?:/)?' => 'reports', // global report queue - '/reports/(global)?(?:/)?(content)/(\%b)/(\d+)(?:/)?' => 'reports', // specific reported content (also historic) - '/reports/(global)?(?:/)?(content)/(\%b)/(\d+)/dismiss(?:/)?' => 'secure report_dismiss', // dismiss all reports on content - '/reports/(global)?(?:/)?(content)/(\%b)/(\d+)/demote(?:/)?' => 'secure report_demote', // demote all reports on content - '/reports/(global)?(?:/)?(content)/(\%b)/(\d+)/promote(?:/)?' => 'secure report_promote', // demote all reports on content - '/reports/(global)?(?:/)?(\d+)/dismiss(all)?(?:/)?' => 'secure report_dismiss', // dismiss a report - '/reports/(global)?(?:/)?(\d+)/demote(?:/)?' => 'secure report_demote', // demote a global report to a local report - '/reports/(global)?(?:/)?(\d+)/promote(?:/)?' => 'secure report_promote', // promote a local report to a global report + '/reports(?:/)?' => 'reports', // report queue + '/reports/(global)?(?:/)?' => 'reports', // global report queue + '/reports/(global)?(?:/)?(content)/(\%b)/(\d+)(?:/)?' => 'reports', // specific reported content (also historic) + '/reports/(global)?(?:/)?(content)/(\%b)/(\d+)/dismiss(?:/)?' => 'secure report_dismiss', // dismiss all reports on content + '/reports/(global)?(?:/)?(content)/(\%b)/(\d+)/demote(?:/)?' => 'secure report_demote', // demote all reports on content + '/reports/(global)?(?:/)?(content)/(\%b)/(\d+)/promote(?:/)?' => 'secure report_promote', // demote all reports on content + '/reports/(global)?(?:/)?(\d+)/dismiss(all)?(?:/)?' => 'secure report_dismiss', // dismiss a report + '/reports/(global)?(?:/)?(\d+)/demote(?:/)?' => 'secure report_demote', // demote a global report to a local report + '/reports/(global)?(?:/)?(\d+)/promote(?:/)?' => 'secure report_promote', // promote a local report to a global report + '/reports/(global)?(?:/)?(\%b)/(un)?clean/(\d+)/(global)?(?:\+)?(local)?' => 'secure report_clean', // protect/unprotect from reports '/IP/([\w.:]+)' => 'secure_POST ip', // view ip address '/IP/([\w.:]+)/remove_note/(\d+)' => 'secure ip_remove_note', // remove note from ip address @@ -98,7 +99,6 @@ $pages = array( '/(\%b)/(un)?lock/(\d+)' => 'secure lock', // lock thread '/(\%b)/(un)?sticky/(\d+)' => 'secure sticky', // sticky thread '/(\%b)/bump(un)?lock/(\d+)' => 'secure bumplock', // "bumplock" thread - '/(\%b)/(un)?clean/(\d+)/(global)?(?:\+)?(local)?' => 'secure clean', // protect/unprotect from reports '/themes' => 'themes_list', // manage themes '/themes/(\w+)' => 'secure_POST theme_configure', // configure/reconfigure theme diff --git a/post.php b/post.php index 29ab8552..099ea6d7 100644 --- a/post.php +++ b/post.php @@ -104,7 +104,8 @@ if (isset($_POST['delete'])) { header('Content-Type: text/json'); echo json_encode(array('success' => true)); } -} elseif (isset($_POST['report'])) { +} +elseif (isset($_POST['report'])) { if (!isset($_POST['board'], $_POST['reason'])) error($config['error']['bot']); @@ -134,26 +135,45 @@ if (isset($_POST['delete'])) { markup($reason); foreach ($report as &$id) { - $query = prepare(sprintf("SELECT `thread` FROM ``posts_%s`` WHERE `id` = :id", $board['uri'])); + $query = prepare( + "SELECT + `thread`, + `post_clean`.`clean_local`, + `post_clean`.`clean_global` + FROM `posts_{$board['uri']}` + LEFT JOIN `post_clean` + ON `post_clean`.`board_id` = '{$board['uri']}' + AND `post_clean`.`post_id` = :id + WHERE `id` = :id" + ); $query->bindValue(':id', $id, PDO::PARAM_INT); $query->execute() or error(db_error($query)); - $thread = $query->fetchColumn(); - - if ($config['syslog']) - _syslog(LOG_INFO, 'Reported post: ' . - '/' . $board['dir'] . $config['dir']['res'] . sprintf($config['file_page'], $thread ? $thread : $id) . ($thread ? '#' . $id : '') . - ' for "' . $reason . '"' - ); - $query = prepare("INSERT INTO ``reports`` (`time`, `ip`, `board`, `post`, `reason`, `local`, `global`) VALUES (:time, :ip, :board, :post, :reason, :local, :global)"); - $query->bindValue(':time', time(), PDO::PARAM_INT); - $query->bindValue(':ip', $_SERVER['REMOTE_ADDR'], PDO::PARAM_STR); - $query->bindValue(':board', $board['uri'], PDO::PARAM_INT); - $query->bindValue(':post', $id, PDO::PARAM_INT); - $query->bindValue(':reason', $reason, PDO::PARAM_STR); - $query->bindValue(':local', 1, PDO::PARAM_BOOL); - $query->bindValue(':global', isset($_POST['global']), PDO::PARAM_BOOL); - $query->execute() or error(db_error($query)); + if( $post = $query->fetch(PDO::FETCH_ASSOC) ) { + $report_local = !$post['clean_local']; + $report_global = isset($_POST['global']) && !$post['clean_global']; + + if( $report_local || $report_global ) { + $thread = $post['thread']; + + if ($config['syslog']) { + _syslog(LOG_INFO, 'Reported post: ' . + '/' . $board['dir'] . $config['dir']['res'] . sprintf($config['file_page'], $thread ? $thread : $id) . ($thread ? '#' . $id : '') . + ' for "' . $reason . '"' + ); + } + + $query = prepare("INSERT INTO `reports` (`time`, `ip`, `board`, `post`, `reason`, `local`, `global`) VALUES (:time, :ip, :board, :post, :reason, :local, :global)"); + $query->bindValue(':time', time(), PDO::PARAM_INT); + $query->bindValue(':ip', $_SERVER['REMOTE_ADDR'], PDO::PARAM_STR); + $query->bindValue(':board', $board['uri'], PDO::PARAM_INT); + $query->bindValue(':post', $id, PDO::PARAM_INT); + $query->bindValue(':reason', $reason, PDO::PARAM_STR); + $query->bindValue(':local', $report_local, PDO::PARAM_BOOL); + $query->bindValue(':global', $report_global, PDO::PARAM_BOOL); + $query->execute() or error(db_error($query)); + } + } } $is_mod = isset($_POST['mod']) && $_POST['mod']; @@ -165,7 +185,8 @@ if (isset($_POST['delete'])) { header('Content-Type: text/json'); echo json_encode(array('success' => true)); } -} elseif (isset($_POST['post'])) { +} +elseif (isset($_POST['post'])) { if (!isset($_POST['body'], $_POST['board'])) error($config['error']['bot']); @@ -890,7 +911,8 @@ if (isset($_POST['delete'])) { 'id' => $id )); } -} elseif (isset($_POST['appeal'])) { +} +elseif (isset($_POST['appeal'])) { if (!isset($_POST['ban_id'])) error($config['error']['bot']); @@ -931,7 +953,8 @@ if (isset($_POST['delete'])) { $query->execute() or error(db_error($query)); displayBan($ban); -} else { +} +else { if (!file_exists($config['has_installed'])) { header('Location: install.php', true, $config['redirect_http']); } else { diff --git a/stylesheets/style.css b/stylesheets/style.css index 61bc07a5..f86a2c13 100644 --- a/stylesheets/style.css +++ b/stylesheets/style.css @@ -289,15 +289,15 @@ div.post.reply { } div.post_modified { - font-size: 10px; min-width: 47.5em; margin-left: 1.8em; padding-top: 0.8em; } div.post_modified div.content-status { - margin-top: 0.4em; + margin-top: 0.5em; padding-bottom: 0em; + font-size: 72%; } span.trip { diff --git a/templates/mod/report.html b/templates/mod/report.html index 5d07e0eb..0080cb51 100644 --- a/templates/mod/report.html +++ b/templates/mod/report.html @@ -32,7 +32,9 @@ {% if global and mod|hasPermission(config.mod.report_demote, report.board) %}