diff --git a/inc/api.php b/inc/api.php
index b2d8adec..b280c25b 100644
--- a/inc/api.php
+++ b/inc/api.php
@@ -32,6 +32,7 @@ class Api {
'images' => 'images',
'sticky' => 'sticky',
'locked' => 'locked',
+ 'cycle' => 'cyclical',
'bump' => 'last_modified',
'embed' => 'embed',
);
diff --git a/inc/config.php b/inc/config.php
index 3fdb8d2f..82fdc882 100644
--- a/inc/config.php
+++ b/inc/config.php
@@ -1245,6 +1245,8 @@
$config['mod']['link_bumpunlock'] = '[-Sage]';
$config['mod']['link_editpost'] = '[Edit]';
$config['mod']['link_move'] = '[Move]';
+ $config['mod']['link_cycle'] = '[Cycle]';
+ $config['mod']['link_uncycle'] = '[-Cycle]';
// Moderator capcodes.
$config['capcode'] = ' ## %s';
@@ -1388,6 +1390,9 @@
$config['mod']['deletebyip_global'] = ADMIN;
// Sticky a thread
$config['mod']['sticky'] = MOD;
+ // Cycle a thread
+ $config['mod']['cycle'] = MOD;
+ $config['cycle_limit'] = &$config['reply_limit'];
// Lock a thread
$config['mod']['lock'] = MOD;
// Post in a locked thread
diff --git a/inc/functions.php b/inc/functions.php
index e9692d56..1bd1f32f 100755
--- a/inc/functions.php
+++ b/inc/functions.php
@@ -1021,7 +1021,7 @@ function insertFloodPost(array $post) {
function post(array $post) {
global $pdo, $board;
- $query = prepare(sprintf("INSERT INTO ``posts_%s`` VALUES ( NULL, :thread, :subject, :email, :name, :trip, :capcode, :body, :body_nomarkup, :time, :time, :files, :num_files, :filehash, :password, :ip, :sticky, :locked, 0, :embed, :slug)", $board['uri']));
+ $query = prepare(sprintf("INSERT INTO ``posts_%s`` VALUES ( NULL, :thread, :subject, :email, :name, :trip, :capcode, :body, :body_nomarkup, :time, :time, :files, :num_files, :filehash, :password, :ip, :sticky, :locked, :cycle, 0, :embed, :slug)", $board['uri']));
// Basic stuff
if (!empty($post['subject'])) {
@@ -1061,6 +1061,12 @@ function post(array $post) {
$query->bindValue(':locked', false, PDO::PARAM_INT);
}
+ if ($post['op'] && $post['mod'] && isset($post['cycle']) && $post['cycle']) {
+ $query->bindValue(':cycle', true, PDO::PARAM_INT);
+ } else {
+ $query->bindValue(':cycle', false, PDO::PARAM_INT);
+ }
+
if ($post['mod'] && isset($post['capcode']) && $post['capcode']) {
$query->bindValue(':capcode', $post['capcode'], PDO::PARAM_INT);
} else {
diff --git a/inc/mod/pages.php b/inc/mod/pages.php
index 6d1e20b4..303fa3dd 100644
--- a/inc/mod/pages.php
+++ b/inc/mod/pages.php
@@ -1089,6 +1089,28 @@ function mod_sticky($board, $unsticky, $post) {
header('Location: ?/' . sprintf($config['board_path'], $board) . $config['file_index'], true, $config['redirect_http']);
}
+function mod_cycle($board, $uncycle, $post) {
+ global $config;
+
+ if (!openBoard($board))
+ error($config['error']['noboard']);
+
+ if (!hasPermission($config['mod']['cycle'], $board))
+ error($config['error']['noaccess']);
+
+ $query = prepare(sprintf('UPDATE ``posts_%s`` SET `cycle` = :cycle WHERE `id` = :id AND `thread` IS NULL', $board));
+ $query->bindValue(':id', $post);
+ $query->bindValue(':cycle', $uncycle ? 0 : 1);
+ $query->execute() or error(db_error($query));
+ if ($query->rowCount()) {
+ modLog(($uncycle ? 'Made not cyclical' : 'Made cyclical') . " thread #{$post}");
+ buildThread($post);
+ buildIndex();
+ }
+
+ header('Location: ?/' . sprintf($config['board_path'], $board) . $config['file_index'], true, $config['redirect_http']);
+}
+
function mod_bumplock($board, $unbumplock, $post) {
global $config;
diff --git a/install.php b/install.php
index 5a6512ba..de4d3dd0 100644
--- a/install.php
+++ b/install.php
@@ -1,7 +1,7 @@
vichan upgrade path.
query("CREATE TABLE IF NOT EXISTS ``search_queries`` ( `ip` varchar(39) NOT NULL, `time` int(11) NOT NULL, `query` text NOT NULL) ENGINE=MyISAM DEFAULT CHARSET=utf8;") or error(db_error());
diff --git a/mod.php b/mod.php
index fbe679ac..0378d55c 100644
--- a/mod.php
+++ b/mod.php
@@ -82,6 +82,7 @@ $pages = array(
'/(\%b)/deletebyip/(\d+)(/global)?' => 'secure deletebyip', // delete all posts by IP address
'/(\%b)/(un)?lock/(\d+)' => 'secure lock', // lock thread
'/(\%b)/(un)?sticky/(\d+)' => 'secure sticky', // sticky thread
+ '/(\%b)/(un)?cycle/(\d+)' => 'secure cycle', // cycle thread
'/(\%b)/bump(un)?lock/(\d+)' => 'secure bumplock', // "bumplock" thread
'/themes' => 'themes_list', // manage themes
diff --git a/post.php b/post.php
index 0d3292bb..98aefe05 100644
--- a/post.php
+++ b/post.php
@@ -265,7 +265,7 @@ if (isset($_POST['delete'])) {
//Check if thread exists
if (!$post['op']) {
- $query = prepare(sprintf("SELECT `sticky`,`locked`,`sage`,`slug` FROM ``posts_%s`` WHERE `id` = :id AND `thread` IS NULL LIMIT 1", $board['uri']));
+ $query = prepare(sprintf("SELECT `sticky`,`locked`,`cycle`,`sage`,`slug` FROM ``posts_%s`` WHERE `id` = :id AND `thread` IS NULL LIMIT 1", $board['uri']));
$query->bindValue(':id', $post['thread'], PDO::PARAM_INT);
$query->execute() or error(db_error());
@@ -867,6 +867,15 @@ if (isset($_POST['delete'])) {
$post['slug'] = slugify($post);
insertFloodPost($post);
+
+ // Handle cyclical threads
+ if (!$post['op'] && isset($thread['cycle']) && $thread['cycle']) {
+ // Query is a bit weird due to "This version of MariaDB doesn't yet support 'LIMIT & IN/ALL/ANY/SOME subquery'" (MariaDB Ver 15.1 Distrib 10.0.17-MariaDB, for Linux (x86_64))
+ $query = prepare(sprintf('DELETE FROM ``posts_%s`` WHERE `thread` = :thread AND `id` NOT IN (SELECT `id` FROM (SELECT `id` FROM ``posts_%s`` WHERE `thread` = :thread ORDER BY `id` DESC LIMIT :limit) i)', $board['uri'], $board['uri']));
+ $query->bindValue(':thread', $post['thread']);
+ $query->bindValue(':limit', $config['cycle_limit'], PDO::PARAM_INT);
+ $query->execute() or error(db_error($query));
+ }
if (isset($post['antispam_hash'])) {
incrementSpamHash($post['antispam_hash']);
diff --git a/templates/post/post_controls.html b/templates/post/post_controls.html
index 99a8484c..60dc6fc4 100644
--- a/templates/post/post_controls.html
+++ b/templates/post/post_controls.html
@@ -41,7 +41,6 @@
{% endif %}
{% endif %}
-
{% if mod|hasPermission(config.mod.move, board.uri) %}
{% if not post.thread %}
{{ config.mod.link_move }}
@@ -49,6 +48,13 @@
{{ config.mod.link_move }}
{% endif %}
{% endif %}
+{% if mod|hasPermission(config.mod.cycle, board.uri) %}
+ {% if post.cycle %}
+ {{ config.mod.link_uncycle }}
+ {% else %}
+ {{ config.mod.link_cycle }}
+ {% endif %}
+{% endif %}
{% if mod|hasPermission(config.mod.editpost, board.uri) %}
{{ config.mod.link_editpost }}
{% endif %}
diff --git a/templates/post_thread.html b/templates/post_thread.html
index 72ca2998..125d5f78 100644
--- a/templates/post_thread.html
+++ b/templates/post_thread.html
@@ -19,25 +19,32 @@
{{ post.id }}
{% if post.sticky %}
{% if config.font_awesome %}
-
+
{% else %}
{% endif %}
{% endif %}
{% if post.locked %}
{% if config.font_awesome %}
-
+
{% else %}
{% endif %}
{% endif %}
{% if post.bumplocked and (config.mod.view_bumplock < 0 or (post.mod and post.mod|hasPermission(config.mod.view_bumplock, board.uri))) %}
{% if config.font_awesome %}
-
+
{% else %}
{% endif %}
{% endif %}
+ {% if post.cycle %}
+ {% if config.font_awesome %}
+
+ {% else %}
+
+ {% endif %}
+ {% endif %}
{% if index %}
[{% trans %}Reply{% endtrans %}]
{% endif %}
diff --git a/templates/posts.sql b/templates/posts.sql
index 6b2249ef..070e687b 100644
--- a/templates/posts.sql
+++ b/templates/posts.sql
@@ -17,6 +17,7 @@ CREATE TABLE IF NOT EXISTS ``posts_{{ board }}`` (
`ip` varchar(39) CHARACTER SET ascii NOT NULL,
`sticky` int(1) NOT NULL,
`locked` int(1) NOT NULL,
+ `cycle` int(1) NOT NULL,
`sage` int(1) NOT NULL,
`embed` text,
`slug` varchar(256) DEFAULT NULL,