diff --git a/README.md b/README.md index 33556ef..2681019 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ Features - Delete post via password. - Management panel: - Administrators and moderators use separate passwords. - - Moderators are only able to sticky threads, delete posts, and approve posts when necessary. (See ``TINYIB_REQMOD``) + - Moderators are only able to sticky threads, lock threads, delete posts, and approve posts when necessary. (See ``TINYIB_REQMOD``) - Ban offensive/abusive posters across all boards. - Post using raw HTML. - Upgrade automatically when installed via git. (Tested on Linux only) @@ -86,9 +86,6 @@ Updating - If other files were updated, and you have made changes yourself: - Visit [GitLab](https://gitlab.com/tslocum/tinyib) and review the changes made in the update. - Ensure the update does not interfere with your changes. - 3. Visit [GitLab](https://gitlab.com/tslocum/tinyib/wikis/NewSQLStructure) and check for new SQL queries which may be required to complete the update. - -**Database structure was last modified on *15th Sep 2015*.** Are you unable to create new posts? Run the SQL on [this page](https://gitlab.com/tslocum/tinyib/wikis/NewSQLStructure) to finish the upgrade process. Migrating ------------ diff --git a/imgboard.php b/imgboard.php index c70047c..e9c17a2 100644 --- a/imgboard.php +++ b/imgboard.php @@ -91,6 +91,15 @@ if (!isset($_GET['delete']) && !isset($_GET['manage']) && (isset($_POST['name']) $post = newPost(setParent()); $hide_fields = $post['parent'] == TINYIB_NEWTHREAD ? $tinyib_hidefieldsop : $tinyib_hidefields; + if ($post['parent'] != TINYIB_NEWTHREAD && !$loggedin) { + $parent = postByID($post['parent']); + if (!isset($parent['locked'])) { + fancyDie("Invalid parent thread ID supplied, unable to create post."); + } else if ($parent['locked'] == 1) { + fancyDie('Replies are not allowed to locked threads.'); + } + } + $post['ip'] = $_SERVER['REMOTE_ADDR']; if ($rawpost || !in_array('name', $hide_fields)) { list($post['name'], $post['tripcode']) = nameAndTripcode($_POST['name']); @@ -443,7 +452,7 @@ if (!isset($_GET['delete']) && !isset($_GET['manage']) && (isset($_POST['name']) if (!$link) { fancyDie("Could not connect to database: " . ((is_object($link)) ? mysqli_error($link) : (($link_error = mysqli_connect_error()) ? $link_error : '(unknown error)'))); } - $db_selected = @mysqli_query($link, "USE " . constant('TINYIB_DBNAME')); + $db_selected = @mysqli_query($link, "USE " . TINYIB_DBNAME); if (!$db_selected) { fancyDie("Could not select database: " . ((is_object($link)) ? mysqli_error($link) : (($link_error = mysqli_connect_error()) ? $link_error : '(unknown error'))); } @@ -543,7 +552,7 @@ if (!isset($_GET['delete']) && !isset($_GET['manage']) && (isset($_POST['name']) if ($_GET['sticky'] > 0) { $post = postByID($_GET['sticky']); if ($post && $post['parent'] == TINYIB_NEWTHREAD) { - stickyThreadByID($post['id'], (intval($_GET['setsticky']))); + stickyThreadByID($post['id'], intval($_GET['setsticky'])); threadUpdated($post['id']); $text .= manageInfo('Thread No.' . $post['id'] . ' ' . (intval($_GET['setsticky']) == 1 ? 'stickied' : 'un-stickied') . '.'); @@ -553,6 +562,20 @@ if (!isset($_GET['delete']) && !isset($_GET['manage']) && (isset($_POST['name']) } else { fancyDie("Form data was lost. Please go back and try again."); } + } elseif (isset($_GET['lock']) && isset($_GET['setlock'])) { + if ($_GET['lock'] > 0) { + $post = postByID($_GET['lock']); + if ($post && $post['parent'] == TINYIB_NEWTHREAD) { + lockThreadByID($post['id'], intval($_GET['setlock'])); + threadUpdated($post['id']); + + $text .= manageInfo('Thread No.' . $post['id'] . ' ' . (intval($_GET['setlock']) == 1 ? 'locked' : 'unlocked') . '.'); + } else { + fancyDie("Sorry, there doesn't appear to be a thread with that ID."); + } + } else { + fancyDie("Form data was lost. Please go back and try again."); + } } elseif (isset($_GET["rawpost"])) { $onload = manageOnLoad("rawpost"); $text .= buildPostForm(0, true); diff --git a/inc/database_flatfile.php b/inc/database_flatfile.php index fd0f5ba..c15e5b4 100644 --- a/inc/database_flatfile.php +++ b/inc/database_flatfile.php @@ -28,6 +28,7 @@ define('POST_THUMB', 19); define('POST_THUMB_WIDTH', 20); define('POST_THUMB_HEIGHT', 21); define('POST_STICKIED', 22); +define('POST_LOCKED', 23); # Ban Structure define('BANS_FILE', '.bans'); @@ -83,10 +84,21 @@ function insertPost($newpost) { $post[POST_THUMB_WIDTH] = $newpost['thumb_width']; $post[POST_THUMB_HEIGHT] = $newpost['thumb_height']; $post[POST_STICKIED] = $newpost['stickied']; + $post[POST_LOCKED] = $newpost['locked']; return $GLOBALS['db']->insertWithAutoId(POSTS_FILE, POST_ID, $post); } +function bumpThreadByID($id) { + $rows = $GLOBALS['db']->selectWhere(POSTS_FILE, new SimpleWhereClause(POST_ID, '=', $id, INTEGER_COMPARISON), 1); + if (count($rows) > 0) { + foreach ($rows as $post) { + $post[POST_BUMPED] = time(); + $GLOBALS['db']->updateRowById(POSTS_FILE, POST_ID, $post); + } + } +} + function stickyThreadByID($id, $setsticky) { $rows = $GLOBALS['db']->selectWhere(POSTS_FILE, new SimpleWhereClause(POST_ID, '=', $id, INTEGER_COMPARISON), 1); if (count($rows) > 0) { @@ -97,11 +109,11 @@ function stickyThreadByID($id, $setsticky) { } } -function bumpThreadByID($id) { +function lockThreadByID($id, $setlock) { $rows = $GLOBALS['db']->selectWhere(POSTS_FILE, new SimpleWhereClause(POST_ID, '=', $id, INTEGER_COMPARISON), 1); if (count($rows) > 0) { foreach ($rows as $post) { - $post[POST_BUMPED] = time(); + $post[POST_LOCKED] = intval($setlock); $GLOBALS['db']->updateRowById(POSTS_FILE, POST_ID, $post); } } @@ -139,6 +151,7 @@ function convertPostsToSQLStyle($posts, $singlepost = false) { $post['thumb_width'] = $oldpost[POST_THUMB_WIDTH]; $post['thumb_height'] = $oldpost[POST_THUMB_HEIGHT]; $post['stickied'] = isset($oldpost[POST_STICKIED]) ? $oldpost[POST_STICKIED] : 0; + $post['locked'] = isset($oldpost[POST_LOCKED]) ? $oldpost[POST_LOCKED] : 0; if ($post['parent'] == '') { $post['parent'] = TINYIB_NEWTHREAD; diff --git a/inc/database_mysql.php b/inc/database_mysql.php index 0418358..6908e98 100644 --- a/inc/database_mysql.php +++ b/inc/database_mysql.php @@ -27,6 +27,14 @@ if (mysql_num_rows(mysql_query("SHOW TABLES LIKE '" . TINYIB_DBBANS . "'")) == 0 mysql_query($bans_sql); } +if (mysql_num_rows(mysql_query("SHOW COLUMNS FROM `" . TINYIB_DBPOSTS . "` LIKE 'stickied'")) == 0) { + mysql_query("ALTER TABLE `" . TINYIB_DBPOSTS . "` ADD COLUMN stickied TINYINT(1) NOT NULL DEFAULT '0'"); +} + +if (mysql_num_rows(mysql_query("SHOW COLUMNS FROM `" . TINYIB_DBPOSTS . "` LIKE 'locked'")) == 0) { + mysql_query("ALTER TABLE `" . TINYIB_DBPOSTS . "` ADD COLUMN locked TINYINT(1) NOT NULL DEFAULT '0'"); +} + # Post Functions function uniquePosts() { $row = mysql_fetch_row(mysql_query("SELECT COUNT(DISTINCT(`ip`)) FROM " . TINYIB_DBPOSTS)); @@ -55,12 +63,16 @@ function approvePostByID($id) { mysql_query("UPDATE `" . TINYIB_DBPOSTS . "` SET `moderated` = 1 WHERE `id` = " . $id . " LIMIT 1"); } +function bumpThreadByID($id) { + mysql_query("UPDATE `" . TINYIB_DBPOSTS . "` SET `bumped` = " . time() . " WHERE `id` = " . $id . " LIMIT 1"); +} + function stickyThreadByID($id, $setsticky) { mysql_query("UPDATE `" . TINYIB_DBPOSTS . "` SET `stickied` = '" . mysql_real_escape_string($setsticky) . "' WHERE `id` = " . $id . " LIMIT 1"); } -function bumpThreadByID($id) { - mysql_query("UPDATE `" . TINYIB_DBPOSTS . "` SET `bumped` = " . time() . " WHERE `id` = " . $id . " LIMIT 1"); +function lockThreadByID($id, $setlock) { + mysql_query("UPDATE `" . TINYIB_DBPOSTS . "` SET `locked` = '" . mysql_real_escape_string($setlock) . "' WHERE `id` = " . $id . " LIMIT 1"); } function countThreads() { diff --git a/inc/database_mysqli.php b/inc/database_mysqli.php index 216597f..7e5974b 100644 --- a/inc/database_mysqli.php +++ b/inc/database_mysqli.php @@ -11,7 +11,7 @@ $link = @mysqli_connect(TINYIB_DBHOST, TINYIB_DBUSERNAME, TINYIB_DBPASSWORD); if (!$link) { fancyDie("Could not connect to database: " . ((is_object($link)) ? mysqli_error($link) : (($link_error = mysqli_connect_error()) ? $link_error : '(unknown error)'))); } -$db_selected = @mysqli_query($link, "USE " . constant('TINYIB_DBNAME')); +$db_selected = @mysqli_query($link, "USE " . TINYIB_DBNAME); if (!$db_selected) { fancyDie("Could not select database: " . ((is_object($link)) ? mysqli_error($link) : (($link_error = mysqli_connect_error()) ? $link_error : '(unknown error'))); } @@ -27,6 +27,14 @@ if (mysqli_num_rows(mysqli_query($link, "SHOW TABLES LIKE '" . TINYIB_DBBANS . " mysqli_query($link, $bans_sql); } +if (mysqli_num_rows(mysqli_query($link, "SHOW COLUMNS FROM `" . TINYIB_DBPOSTS . "` LIKE 'stickied'")) == 0) { + mysqli_query($link,"ALTER TABLE `" . TINYIB_DBPOSTS . "` ADD COLUMN stickied TINYINT(1) NOT NULL DEFAULT '0'"); +} + +if (mysqli_num_rows(mysqli_query($link, "SHOW COLUMNS FROM `" . TINYIB_DBPOSTS . "` LIKE 'locked'")) == 0) { + mysqli_query($link,"ALTER TABLE `" . TINYIB_DBPOSTS . "` ADD COLUMN locked TINYINT(1) NOT NULL DEFAULT '0'"); +} + # Post Functions function uniquePosts() { global $link; @@ -60,14 +68,19 @@ function approvePostByID($id) { mysqli_query($link, "UPDATE `" . TINYIB_DBPOSTS . "` SET `moderated` = 1 WHERE `id` = " . $id . " LIMIT 1"); } +function bumpThreadByID($id) { + global $link; + mysqli_query($link, "UPDATE `" . TINYIB_DBPOSTS . "` SET `bumped` = " . time() . " WHERE `id` = " . $id . " LIMIT 1"); +} + function stickyThreadByID($id, $setsticky) { global $link; mysqli_query($link, "UPDATE `" . TINYIB_DBPOSTS . "` SET `stickied` = '" . mysqli_real_escape_string($link, $setsticky) . "' WHERE `id` = " . $id . " LIMIT 1"); } -function bumpThreadByID($id) { +function lockThreadByID($id, $setlock) { global $link; - mysqli_query($link, "UPDATE `" . TINYIB_DBPOSTS . "` SET `bumped` = " . time() . " WHERE `id` = " . $id . " LIMIT 1"); + mysqli_query($link, "UPDATE `" . TINYIB_DBPOSTS . "` SET `locked` = '" . mysqli_real_escape_string($link, $setlock) . "' WHERE `id` = " . $id . " LIMIT 1"); } function countThreads() { diff --git a/inc/database_pdo.php b/inc/database_pdo.php index 01fb634..ba6d826 100644 --- a/inc/database_pdo.php +++ b/inc/database_pdo.php @@ -54,7 +54,31 @@ if (!$bans_exists) { $dbh->exec($bans_sql); } -# Utililty +if (TINYIB_DBDRIVER === 'pgsql') { + $query = "SELECT column_name FROM information_schema.columns WHERE table_name='" . TINYIB_DBPOSTS . "' and column_name='stickied'"; + $stickied_exists = $dbh->query($query)->fetchColumn() != 0; +} else { + $dbh->query("SHOW COLUMNS FROM `" . TINYIB_DBPOSTS . "` LIKE 'stickied'"); + $stickied_exists = $dbh->query("SELECT FOUND_ROWS()")->fetchColumn() != 0; +} + +if (!$stickied_exists) { + $dbh->exec("ALTER TABLE `" . TINYIB_DBPOSTS . "` ADD COLUMN stickied TINYINT(1) NOT NULL DEFAULT '0'"); +} + +if (TINYIB_DBDRIVER === 'pgsql') { + $query = "SELECT column_name FROM information_schema.columns WHERE table_name='" . TINYIB_DBPOSTS . "' and column_name='locked'"; + $stickied_exists = $dbh->query($query)->fetchColumn() != 0; +} else { + $dbh->query("SHOW COLUMNS FROM `" . TINYIB_DBPOSTS . "` LIKE 'locked'"); + $stickied_exists = $dbh->query("SELECT FOUND_ROWS()")->fetchColumn() != 0; +} + +if (!$stickied_exists) { + $dbh->exec("ALTER TABLE `" . TINYIB_DBPOSTS . "` ADD COLUMN locked TINYINT(1) NOT NULL DEFAULT '0'"); +} + +# Utility function pdoQuery($sql, $params = false) { global $dbh; @@ -102,13 +126,17 @@ function approvePostByID($id) { pdoQuery("UPDATE " . TINYIB_DBPOSTS . " SET moderated = ? WHERE id = ?", array('1', $id)); } +function bumpThreadByID($id) { + $now = time(); + pdoQuery("UPDATE " . TINYIB_DBPOSTS . " SET bumped = ? WHERE id = ?", array($now, $id)); +} + function stickyThreadByID($id, $setsticky) { pdoQuery("UPDATE " . TINYIB_DBPOSTS . " SET stickied = ? WHERE id = ?", array($setsticky, $id)); } -function bumpThreadByID($id) { - $now = time(); - pdoQuery("UPDATE " . TINYIB_DBPOSTS . " SET bumped = ? WHERE id = ?", array($now, $id)); +function lockThreadByID($id, $setlock) { + pdoQuery("UPDATE " . TINYIB_DBPOSTS . " SET locked = ? WHERE id = ?", array($setlock, $id)); } function countThreads() { diff --git a/inc/database_sqlite.php b/inc/database_sqlite.php index daeff65..a972ae4 100644 --- a/inc/database_sqlite.php +++ b/inc/database_sqlite.php @@ -56,6 +56,9 @@ if (sqlite_num_rows($result) == 0) { // Add stickied column if it isn't present sqlite_query($db, "ALTER TABLE " . TINYIB_DBPOSTS . " ADD COLUMN stickied INTEGER NOT NULL DEFAULT '0'"); +// Add locked column if it isn't present +sqlite_query($db, "ALTER TABLE " . TINYIB_DBPOSTS . " ADD COLUMN locked INTEGER NOT NULL DEFAULT '0'"); + # Post Functions function uniquePosts() { return sqlite_fetch_single(sqlite_query($GLOBALS["db"], "SELECT COUNT(ip) FROM (SELECT DISTINCT ip FROM " . TINYIB_DBPOSTS . ")")); @@ -77,12 +80,16 @@ function insertPost($post) { return sqlite_last_insert_rowid($GLOBALS["db"]); } +function bumpThreadByID($id) { + sqlite_query($GLOBALS["db"], "UPDATE " . TINYIB_DBPOSTS . " SET bumped = " . time() . " WHERE id = " . $id); +} + function stickyThreadByID($id, $setsticky) { sqlite_query($GLOBALS["db"], "UPDATE " . TINYIB_DBPOSTS . " SET stickied = '" . sqlite_escape_string($setsticky) . "' WHERE id = " . $id); } -function bumpThreadByID($id) { - sqlite_query($GLOBALS["db"], "UPDATE " . TINYIB_DBPOSTS . " SET bumped = " . time() . " WHERE id = " . $id); +function lockThreadByID($id, $setlock) { + sqlite_query($GLOBALS["db"], "UPDATE " . TINYIB_DBPOSTS . " SET locked = '" . sqlite_escape_string($setlock) . "' WHERE id = " . $id); } function countThreads() { diff --git a/inc/database_sqlite3.php b/inc/database_sqlite3.php index 4c795b3..4ab0b02 100644 --- a/inc/database_sqlite3.php +++ b/inc/database_sqlite3.php @@ -57,6 +57,9 @@ if (!$result->fetchArray()) { // Add stickied column if it isn't present @$db->exec("ALTER TABLE " . TINYIB_DBPOSTS . " ADD COLUMN stickied INTEGER NOT NULL DEFAULT '0'"); +// Add locked column if it isn't present +@$db->exec("ALTER TABLE " . TINYIB_DBPOSTS . " ADD COLUMN locked INTEGER NOT NULL DEFAULT '0'"); + # Post Functions function uniquePosts() { global $db; @@ -82,14 +85,19 @@ function insertPost($post) { return $db->lastInsertRowID(); } +function bumpThreadByID($id) { + global $db; + $db->exec("UPDATE " . TINYIB_DBPOSTS . " SET bumped = " . time() . " WHERE id = " . $id); +} + function stickyThreadByID($id, $setsticky) { global $db; $db->exec("UPDATE " . TINYIB_DBPOSTS . " SET stickied = '" . $db->escapeString($setsticky) . "' WHERE id = " . $id); } -function bumpThreadByID($id) { +function lockThreadByID($id, $setlock) { global $db; - $db->exec("UPDATE " . TINYIB_DBPOSTS . " SET bumped = " . time() . " WHERE id = " . $id); + $db->exec("UPDATE " . TINYIB_DBPOSTS . " SET locked = '" . $db->escapeString($setlock) . "' WHERE id = " . $id); } function countThreads() { diff --git a/inc/functions.php b/inc/functions.php index 034400f..b81d9e3 100644 --- a/inc/functions.php +++ b/inc/functions.php @@ -27,8 +27,9 @@ if (TINYIB_DBMODE == 'pdo' && TINYIB_DBDRIVER == 'pgsql') { "thumb" varchar(255) NOT NULL, "thumb_width" smallint NOT NULL default \'0\', "thumb_height" smallint NOT NULL default \'0\', - "stickied" smallint NOT NULL default \'0\', "moderated" smallint NOT NULL default \'1\', + "stickied" smallint NOT NULL default \'0\', + "locked" smallint NOT NULL default \'0\', PRIMARY KEY ("id") ); CREATE INDEX ON "' . TINYIB_DBPOSTS . '"("parent"); @@ -231,8 +232,8 @@ function writePage($filename, $contents) { } function fixLinksInRes($html) { - $search = array(' href="css/', ' src="js/', ' href="src/', ' href="thumb/', ' href="res/', ' href="imgboard.php', ' href="favicon.ico', 'src="thumb/', 'src="inc/', 'src="sticky.png', ' action="imgboard.php'); - $replace = array(' href="../css/', ' src="../js/', ' href="../src/', ' href="../thumb/', ' href="../res/', ' href="../imgboard.php', ' href="../favicon.ico', 'src="../thumb/', 'src="../inc/', 'src="../sticky.png', ' action="../imgboard.php'); + $search = array(' href="css/', ' src="js/', ' href="src/', ' href="thumb/', ' href="res/', ' href="imgboard.php', ' href="favicon.ico', 'src="thumb/', 'src="inc/', 'src="sticky.png', 'src="lock.png', ' action="imgboard.php'); + $replace = array(' href="../css/', ' src="../js/', ' href="../src/', ' href="../thumb/', ' href="../res/', ' href="../imgboard.php', ' href="../favicon.ico', 'src="../thumb/', 'src="../inc/', 'src="../sticky.png', 'src="../lock.png', ' action="../imgboard.php'); return str_replace($search, $replace, $html); } diff --git a/inc/html.php b/inc/html.php index 5ca0351..b37bd80 100644 --- a/inc/html.php +++ b/inc/html.php @@ -336,6 +336,10 @@ function buildPost($post, $res) { $reflink .= ' Stickied'; } + if ($post["locked"] == 1) { + $reflink .= ' Locked'; + } + if (!isset($post["omitted"])) { $post["omitted"] = 0; } @@ -703,6 +707,7 @@ function manageModeratePost($post) { $post_or_thread = ($post['parent'] == TINYIB_NEWTHREAD) ? 'Thread' : 'Post'; $sticky_html = ""; + $lock_html = ""; if ($post["parent"] == TINYIB_NEWTHREAD) { $sticky_set = $post['stickied'] == 1 ? '0' : '1'; $sticky_unsticky = $post['stickied'] == 1 ? 'Un-sticky' : 'Sticky'; @@ -719,6 +724,20 @@ function manageModeratePost($post) { $sticky_unsticky_help EOF; + $lock_set = $post['locked'] == 1 ? '0' : '1'; + $lock_label = $post['locked'] == 1 ? 'Unlock' : 'Lock'; + $lock_help = $post['locked'] == 1 ? 'Allow replying to this thread.' : 'Disallow replying to this thread.'; + $lock_html = << +
+ + + + +
+ $lock_help +EOF; + $post_html = ""; $posts = postsInThreadByID($post["id"]); foreach ($posts as $post_temp) { @@ -757,6 +776,8 @@ EOF; $sticky_html + $lock_html + diff --git a/lock.png b/lock.png new file mode 100644 index 0000000..3b47405 Binary files /dev/null and b/lock.png differ