diff --git a/inc/8chan-mod-pages.php b/inc/8chan-mod-pages.php index f437f92e..2b09d098 100644 --- a/inc/8chan-mod-pages.php +++ b/inc/8chan-mod-pages.php @@ -49,6 +49,7 @@ $config['mod']['unban'] = BOARDVOLUNTEER; $config['mod']['deletebyip'] = BOARDVOLUNTEER; $config['mod']['sticky'] = BOARDVOLUNTEER; + $config['mod']['cycle'] = BOARDVOLUNTEER; $config['mod']['lock'] = BOARDVOLUNTEER; $config['mod']['postinlocked'] = BOARDVOLUNTEER; $config['mod']['bumplock'] = BOARDVOLUNTEER; @@ -246,22 +247,30 @@ if (!is_dir($dir)){ mkdir($dir, 0777, true); } - - if (isset($_FILES['file'])){ - if (!isset($_POST['description']) and $_POST['description']) + + function handle_file($id = false, $description, $b, $dir) { + global $config; + + if (!isset($description) and $description) error(_('You must enter a flag description!')); - if (strlen($_POST['description']) > 255) + if (strlen($description) > 255) error(_('Flag description too long!')); - $upload = $_FILES['file']['tmp_name']; + if ($id) { + $f = 'flag-'.$id; + } else { + $f = 'file'; + $id = time() . substr(microtime(), 2, 3); + } + + $upload = $_FILES[$f]['tmp_name']; $banners = array_diff(scandir($dir), array('..', '.')); if (!is_readable($upload)) error($config['error']['nomove']); - $id = time() . substr(microtime(), 2, 3); - $extension = strtolower(mb_substr($_FILES['file']['name'], mb_strrpos($_FILES['file']['name'], '.') + 1)); + $extension = strtolower(mb_substr($_FILES[$f]['name'], mb_strrpos($_FILES[$f]['name'], '.') + 1)); if ($extension != 'png') { error(_('Flags must be in PNG format.')); @@ -283,8 +292,45 @@ } copy($upload, "$dir/$id.$extension"); - $config['user_flags'][$id] = utf8tohtml($_POST['description']); + purge("$dir/$id.$extension"); + $config['user_flags'][$id] = utf8tohtml($description); + file_write($b.'/flags.ser', serialize($config['user_flags'])); + } + + // Handle a new flag, if any. + if (isset($_FILES['file'])){ + handle_file(false, $_POST['description'], $b, $dir); + } + // Handle edits to existing flags. + foreach ($_FILES as $k => $a) { + if (empty($_FILES[$k]['tmp_name'])) continue; + + if (preg_match('/^flag-(\d+)$/', $k, $matches)) { + $id = (int)$matches[1]; + if (!isset($_POST['description-'.$id])) continue; + + if (isset($config['user_flags'][$id])) { + handle_file($id, $_POST['description-'.$id], $b, $dir); + } + } + } + + // Description just changed, flag not edited. + foreach ($_POST as $k => $v) { + if (!preg_match('/^description-(\d+)$/', $k, $matches)) continue; + $id = (int)$matches[1]; + if (!isset($_POST['description-'.$id])) continue; + + $description = $_POST['description-'.$id]; + + if (strlen($description) > 255) + error(_('Flag description too long!')); + $config['user_flags'][$id] = utf8tohtml($description); + file_write($b.'/flags.ser', serialize($config['user_flags'])); + } + + if ($_SERVER['REQUEST_METHOD'] === 'POST') { $flags = << $d){ if (!preg_match('/[0-9+]/', $d)){ diff --git a/inc/api.php b/inc/api.php index 9329fc4d..b278da96 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 37925a3b..f08ce7bf 100644 --- a/inc/config.php +++ b/inc/config.php @@ -1272,6 +1272,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'; @@ -1415,6 +1417,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 683ec275..8674ecd0 100755 --- a/inc/functions.php +++ b/inc/functions.php @@ -504,6 +504,8 @@ function boardTitle($uri) { function purge($uri) { global $config, $debug; + if (!isset($config['purge'])) return; + // Fix for Unicode $uri = rawurlencode($uri); @@ -913,7 +915,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, NULL)", $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, NULL)", $board['uri'])); // Basic stuff if (!empty($post['subject'])) { @@ -953,6 +955,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 1049531a..7efabae6 100644 --- a/inc/mod/pages.php +++ b/inc/mod/pages.php @@ -1160,6 +1160,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; @@ -1593,10 +1615,17 @@ function mod_edit_post($board, $edit_raw_html, $postID) { $_POST['body'] .= "$value"; } + // Handle embed edits... + foreach ($config['embedding'] as &$embed) { + if (preg_match($embed[0], $_POST['embed'])) { + $embed_link = $_POST['embed']; + } + } + if ($edit_raw_html) - $query = prepare(sprintf('UPDATE ``posts_%s`` SET `name` = :name,'. $trip .' `email` = :email, `subject` = :subject, `body` = :body, `body_nomarkup` = :body_nomarkup, `edited_at` = UNIX_TIMESTAMP(NOW()) WHERE `id` = :id', $board)); + $query = prepare(sprintf('UPDATE ``posts_%s`` SET `name` = :name,'. $trip .' `email` = :email, `subject` = :subject, `body` = :body, `body_nomarkup` = :body_nomarkup, `embed` = :embed `edited_at` = UNIX_TIMESTAMP(NOW()) WHERE `id` = :id', $board)); else - $query = prepare(sprintf('UPDATE ``posts_%s`` SET `name` = :name,'. $trip .' `email` = :email, `subject` = :subject, `body_nomarkup` = :body, `edited_at` = UNIX_TIMESTAMP(NOW()) WHERE `id` = :id', $board)); + $query = prepare(sprintf('UPDATE ``posts_%s`` SET `name` = :name,'. $trip .' `email` = :email, `subject` = :subject, `body_nomarkup` = :body, `embed` = :embed, `edited_at` = UNIX_TIMESTAMP(NOW()) WHERE `id` = :id', $board)); $query->bindValue(':id', $postID); $query->bindValue(':name', $_POST['name'] ? $_POST['name'] : $config['anonymous']); $query->bindValue(':email', $_POST['email']); @@ -1606,6 +1635,11 @@ function mod_edit_post($board, $edit_raw_html, $postID) { $body_nomarkup = $_POST['body'] . "\n1"; $query->bindValue(':body_nomarkup', $body_nomarkup); } + if (isset($embed_link)) { + $query->bindValue(':embed', $embed_link); + } else { + $query->bindValue(':embed', NULL, PDO::PARAM_NULL); + } $query->execute() or error(db_error($query)); if( $config['clean']['edits_remove_local'] || $config['clean']['edits_remove_global'] ) { @@ -1664,7 +1698,10 @@ function mod_edit_post($board, $edit_raw_html, $postID) { $post['body'] = str_replace("\t", ' ', $post['body']); } - mod_page(_('Edit post'), 'mod/edit_post_form.html', array('token' => $security_token, 'board' => $board, 'raw' => $edit_raw_html, 'post' => $post)); + $preview = new Post($post); + $html = $preview->build(true); + + mod_page(_('Edit post'), 'mod/edit_post_form.html', array('token' => $security_token, 'board' => $board, 'raw' => $edit_raw_html, 'post' => $post, 'preview' => $html)); } } diff --git a/mod.php b/mod.php index 89ea09a1..907f7bc2 100644 --- a/mod.php +++ b/mod.php @@ -94,6 +94,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 bb1203f3..16c6a71d 100644 --- a/post.php +++ b/post.php @@ -315,7 +315,7 @@ elseif (isset($_POST['post'])) { //Check if thread exists if (!$post['op']) { - $query = prepare(sprintf("SELECT `sticky`,`locked`,`sage` FROM ``posts_%s`` WHERE `id` = :id AND `thread` IS NULL LIMIT 1", $board['uri'])); + $query = prepare(sprintf("SELECT `sticky`,`locked`,`cycle`,`sage` 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()); @@ -905,6 +905,19 @@ elseif (isset($_POST['post'])) { $post['id'] = $id = post($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('SELECT `id` 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)); + + while ($dpost = $query->fetch()) { + deletePost($dpost['id'], false, false); + } + } if (isset($post['antispam_hash'])) { incrementSpamHash($post['antispam_hash']); diff --git a/templates/mod/edit_post_form.html b/templates/mod/edit_post_form.html index d40d9b05..b36044f8 100644 --- a/templates/mod/edit_post_form.html +++ b/templates/mod/edit_post_form.html @@ -1,3 +1,5 @@ +
+
@@ -15,7 +17,7 @@ {% trans %}Tripcode{% endtrans %} - Remove? + {% trans %}Remove tripcode?{% endtrans %} @@ -43,7 +45,28 @@ + {# + + {% trans %}Files{% endtrans %}
+

{% trans %}Note: Changing files
deletes all previous ones.{% endtrans %}

+ + + {% for i in range(0, config.max_images - 1) %} +
+ {% endfor %} + + #} + + + {% trans %}Embed{% endtrans %} + + + + + +

{% trans %}Existing post{% endtrans %}

+ {{ preview }}

{% if mod|hasPermission(config.mod.rawhtml) %} {% if raw %} @@ -55,3 +78,4 @@ {% endif %}

+
diff --git a/templates/mod/flags.html b/templates/mod/flags.html index d78f8e21..b804e51b 100644 --- a/templates/mod/flags.html +++ b/templates/mod/flags.html @@ -14,18 +14,19 @@

{% trans %}Flags already in use{% endtrans %}

-
+ + {% for flag, description in config.user_flags %} - + {% endfor %}
D{% trans %}Flag image{% endtrans %}{% trans %}Flag description{% endtrans %}
{{description}}
-

+

diff --git a/templates/mod/settings.html b/templates/mod/settings.html index f7be4866..660bb684 100644 --- a/templates/mod/settings.html +++ b/templates/mod/settings.html @@ -1,5 +1,5 @@ - +

{% trans %}Tip: Some changes made on this page won't take effect until a new post is made on your board.{% endtrans %}

diff --git a/templates/post/post_controls.html b/templates/post/post_controls.html index 9d0fe24f..30f9ada2 100644 --- a/templates/post/post_controls.html +++ b/templates/post/post_controls.html @@ -44,7 +44,6 @@ {% endif %} {% endif %} - {% if mod|hasPermission(config.mod.move, board.uri) %} {% if not post.thread %} {{ config.mod.link_move }}  @@ -52,6 +51,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 7bfbd89b..6bdf3d95 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 %} Sticky {% endif %} {% endif %} {% if post.locked %} {% if config.font_awesome %} - + {% else %} Locked {% 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 %} Bumplocked {% endif %} {% endif %} + {% if post.cycle %} + {% if config.font_awesome %} + + {% else %} + Cyclical + {% endif %} + {% endif %} {% if index %} [{% trans %}Reply{% endtrans %}] {% endif %} diff --git a/templates/posts.sql b/templates/posts.sql index 47c0a65d..21c54fbb 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, `edited_at` int(11) DEFAULT NULL, diff --git a/tools/i18n_extract.php b/tools/i18n_extract.php index a1492a77..088adfed 100755 --- a/tools/i18n_extract.php +++ b/tools/i18n_extract.php @@ -39,10 +39,10 @@ foreach ($locales as $loc) { if (file_exists($locdir."/LC_MESSAGES/tinyboard.po")) $join = "-j --omit-header"; else $join = ""; passthru("cd $locdir/LC_MESSAGES; - xgettext -d tinyboard -L php --from-code utf-8 $join -c $(find ../../../../ -name \*.php)"); + xgettext -d tinyboard -L php --from-code utf-8 $join $(find ../../../../ -name \*.php)"); // Generate javascript.po passthru("cd $locdir/LC_MESSAGES;". - "xgettext -d javascript -L Python --force-po --from-code utf-8 $join -c ". + "xgettext -d javascript -L Python --force-po --from-code utf-8 $join ". "$(find ../../../../js/ ../../../../templates/ -not -path \*node_modules\* -name \*.js)"); } diff --git a/tools/migrate_cycle.php b/tools/migrate_cycle.php new file mode 100644 index 00000000..c7f05336 --- /dev/null +++ b/tools/migrate_cycle.php @@ -0,0 +1,11 @@ + $b) { + query(sprintf('ALTER TABLE ``posts_%s`` ADD COLUMN cycle INT(1) NOT NULL AFTER locked', $b)); +}