diff --git a/inc/Data/Driver/ErrorLogLogDriver.php b/inc/Data/Driver/ErrorLogLogDriver.php
deleted file mode 100644
index e2050606..00000000
--- a/inc/Data/Driver/ErrorLogLogDriver.php
+++ /dev/null
@@ -1,28 +0,0 @@
-name = $name;
- $this->level = $level;
- }
-
- public function log(int $level, string $message): void {
- if ($level <= $this->level) {
- $lv = $this->levelToString($level);
- $line = "{$this->name} $lv: $message";
- \error_log($line, 0, null, null);
- }
- }
-}
diff --git a/inc/Data/Driver/FileLogDriver.php b/inc/Data/Driver/FileLogDriver.php
deleted file mode 100644
index 2c9f14a0..00000000
--- a/inc/Data/Driver/FileLogDriver.php
+++ /dev/null
@@ -1,61 +0,0 @@
-fd = \fopen($file_path, 'a');
- if ($this->fd === false) {
- throw new \RuntimeException("Unable to open log file at $file_path");
- }
-
- $this->name = $name;
- $this->level = $level;
-
- // In some cases PHP does not run the destructor.
- \register_shutdown_function([$this, 'close']);
- }
-
- public function __destruct() {
- $this->close();
- }
-
- public function log(int $level, string $message): void {
- if ($level <= $this->level) {
- $lv = $this->levelToString($level);
- $line = "{$this->name} $lv: $message\n";
- \flock($this->fd, LOCK_EX);
- \fwrite($this->fd, $line);
- \fflush($this->fd);
- \flock($this->fd, LOCK_UN);
- }
- }
-
- public function close() {
- \flock($this->fd, LOCK_UN);
- \fclose($this->fd);
- }
-}
diff --git a/inc/Data/Driver/LogDriver.php b/inc/Data/Driver/LogDriver.php
deleted file mode 100644
index fddc3f27..00000000
--- a/inc/Data/Driver/LogDriver.php
+++ /dev/null
@@ -1,22 +0,0 @@
-name = $name;
- $this->level = $level;
- }
-
- public function log(int $level, string $message): void {
- if ($level <= $this->level) {
- $lv = $this->levelToString($level);
- \fwrite(\STDERR, "{$this->name} $lv: $message\n");
- }
- }
-}
diff --git a/inc/Data/Driver/SyslogLogDriver.php b/inc/Data/Driver/SyslogLogDriver.php
deleted file mode 100644
index c0df5304..00000000
--- a/inc/Data/Driver/SyslogLogDriver.php
+++ /dev/null
@@ -1,35 +0,0 @@
-level = $level;
- }
-
- public function log(int $level, string $message): void {
- if ($level <= $this->level) {
- if (isset($_SERVER['REMOTE_ADDR'], $_SERVER['REQUEST_METHOD'], $_SERVER['REQUEST_URI'])) {
- // CGI
- \syslog($level, "$message - client: {$_SERVER['REMOTE_ADDR']}, request: \"{$_SERVER['REQUEST_METHOD']} {$_SERVER['REQUEST_URI']}\"");
- } else {
- \syslog($level, $message);
- }
- }
- }
-}
diff --git a/inc/Data/IpNoteQueries.php b/inc/Data/IpNoteQueries.php
deleted file mode 100644
index ba6fdb15..00000000
--- a/inc/Data/IpNoteQueries.php
+++ /dev/null
@@ -1,76 +0,0 @@
-pdo = $pdo;
- $this->cache = $cache;
- }
-
- /**
- * Get all the notes relative to an IP.
- *
- * @param string $ip The IP of the notes. THE STRING IS NOT VALIDATED.
- * @return array Returns an array of notes sorted by the most recent. Includes the username of the mods.
- */
- public function getByIp(string $ip) {
- $ret = $this->cache->get("ip_note_queries_$ip");
- if ($ret !== null) {
- return $ret;
- }
-
- $query = $this->pdo->prepare('SELECT `ip_notes`.*, `username` FROM `ip_notes` LEFT JOIN `mods` ON `mod` = `mods`.`id` WHERE `ip` = :ip ORDER BY `time` DESC');
- $query->bindValue(':ip', $ip);
- $query->execute();
- $ret = $query->fetchAll(\PDO::FETCH_ASSOC);
-
- $this->cache->set("ip_note_queries_$ip", $ret);
- return $ret;
- }
-
- /**
- * Creates a new note relative to the given ip.
- *
- * @param string $ip The IP of the note. THE STRING IS NOT VALIDATED.
- * @param int $mod_id The id of the mod who created the note.
- * @param string $body The text of the note.
- * @return void
- */
- public function add(string $ip, int $mod_id, string $body) {
- $query = $this->pdo->prepare('INSERT INTO `ip_notes` (`ip`, `mod`, `time`, `body`) VALUES (:ip, :mod, :time, :body)');
- $query->bindValue(':ip', $ip);
- $query->bindValue(':mod', $mod_id);
- $query->bindValue(':time', time());
- $query->bindValue(':body', $body);
- $query->execute();
-
- $this->cache->delete("ip_note_queries_$ip");
- }
-
- /**
- * Delete a note only if it's of a particular IP address.
- *
- * @param int $id The id of the note.
- * @param int $ip The expected IP of the note. THE STRING IS NOT VALIDATED.
- * @return bool True if any note was deleted.
- */
- public function deleteWhereIp(int $id, string $ip): bool {
- $query = $this->pdo->prepare('DELETE FROM `ip_notes` WHERE `ip` = :ip AND `id` = :id');
- $query->bindValue(':ip', $ip);
- $query->bindValue(':id', $id);
- $query->execute();
- $any = $query->rowCount() != 0;
-
- if ($any) {
- $this->cache->delete("ip_note_queries_$ip");
- }
- return $any;
- }
-}
diff --git a/inc/Data/UserPostQueries.php b/inc/Data/UserPostQueries.php
index 1c203431..8f803b93 100644
--- a/inc/Data/UserPostQueries.php
+++ b/inc/Data/UserPostQueries.php
@@ -44,20 +44,19 @@ class UserPostQueries {
$posts_count = \count($posts);
- // By fetching one extra post bellow and/or above the limit, we know if there are any posts beside the current page.
if ($posts_count === $page_size + 2) {
$has_extra_prev_post = true;
$has_extra_end_post = true;
- } else {
- /*
- * If the id we start fetching from is also the first id fetched from the DB, then we exclude it from
- * the results, noting that we fetched 1 more posts than we needed, and it was before the current page.
- * Hence, we have no extra post at the end and no next page.
- */
+ } elseif ($posts_count === $page_size + 1) {
$has_extra_prev_post = $start_id !== null && $start_id === (int)$posts[0]['id'];
- $has_extra_end_post = !$has_extra_prev_post && $posts_count > $page_size;
+ $has_extra_end_post = !$has_extra_prev_post;
+ } else {
+ $has_extra_prev_post = false;
+ $has_extra_end_post = false;
}
+ // Since we fetched one post bellow and/or above the limit, we always know if there are any posts after the current page.
+
// Get the previous cursor, if any.
if ($has_extra_prev_post) {
\array_shift($posts);
diff --git a/inc/config.php b/inc/config.php
index 71b0fbf4..def2cd27 100644
--- a/inc/config.php
+++ b/inc/config.php
@@ -63,29 +63,9 @@
// been generated. This keeps the script from querying the database and causing strain when not needed.
$config['has_installed'] = '.installed';
- // Deprecated, use 'log_system'.
+ // Use syslog() for logging all error messages and unauthorized login attempts.
$config['syslog'] = false;
- $config['log_system'] = [
- /*
- * Log all error messages and unauthorized login attempts.
- * Can be "syslog", "error_log" (default), "file", or "stderr".
- */
- 'type' => 'error_log',
- // The application name used by the logging system. Defaults to "tinyboard" for backwards compatibility.
- 'name' => 'tinyboard',
- /*
- * Only relevant if 'log_system' is set to "syslog". If true, double print the logs also in stderr. Defaults to
- * false.
- */
- 'syslog_stderr' => false,
- /*
- * Only relevant if "log_system" is set to `file`. Sets the file that vichan will log to. Defaults to
- * '/var/log/vichan.log'.
- */
- 'file_path' => '/var/log/vichan.log',
- ];
-
// Use `host` via shell_exec() to lookup hostnames, avoiding query timeouts. May not work on your system.
// Requires safe_mode to be disabled.
$config['dns_system'] = false;
@@ -943,6 +923,10 @@
// Location of thumbnail to use for deleted images.
$config['image_deleted'] = 'static/deleted.png';
+ // When a thumbnailed image is going to be the same (in dimension), just copy the entire file and use
+ // that as a thumbnail instead of resizing/redrawing.
+ $config['minimum_copy_resize'] = false;
+
// Maximum image upload size in bytes.
$config['max_filesize'] = 10 * 1024 * 1024; // 10MB
// Maximum image dimensions.
@@ -981,6 +965,15 @@
// Set this to true if you're using Linux and you can execute `md5sum` binary.
$config['gnu_md5'] = false;
+ // Use Tesseract OCR to retrieve text from images, so you can use it as a spamfilter.
+ $config['tesseract_ocr'] = false;
+
+ // Tesseract parameters
+ $config['tesseract_params'] = '';
+
+ // Tesseract preprocess command
+ $config['tesseract_preprocess_command'] = 'convert -monochrome %s -';
+
// Number of posts in a "View Last X Posts" page
$config['noko50_count'] = 50;
// Number of posts a thread needs before it gets a "View Last X Posts" page.
diff --git a/inc/context.php b/inc/context.php
index 11a153ec..c744f9d8 100644
--- a/inc/context.php
+++ b/inc/context.php
@@ -1,8 +1,8 @@
$config,
- LogDriver::class => function($c) {
- $config = $c->get('config');
-
- $name = $config['log_system']['name'];
- $level = $config['debug'] ? LogDriver::DEBUG : LogDriver::NOTICE;
- $backend = $config['log_system']['type'];
-
- $legacy_syslog = isset($config['syslog']) && $config['syslog'];
-
- // Check 'syslog' for backwards compatibility.
- if ($legacy_syslog || $backend === 'syslog') {
- $log_driver = new SyslogLogDriver($name, $level, $config['log_system']['syslog_stderr']);
- if ($legacy_syslog) {
- $log_driver->log(LogDriver::NOTICE, 'The configuration setting \'syslog\' is deprecated. Please use \'log_system\' instead');
- }
- return $log_driver;
- } elseif ($backend === 'file') {
- return new FileLogDriver($name, $level, $config['log_system']['file_path']);
- } elseif ($backend === 'stderr') {
- return new StderrLogDriver($name, $level);
- } elseif ($backend === 'error_log') {
- return new ErrorLogLogDriver($name, $level);
- } else {
- $log_driver = new ErrorLogLogDriver($name, $level);
- $log_driver->log(LogDriver::ERROR, "Unknown 'log_system' value '$backend', using 'error_log' default");
- return $log_driver;
- }
- },
CacheDriver::class => function($c) {
// Use the global for backwards compatibility.
return \cache::getCache();
@@ -76,7 +48,6 @@ function build_context(array $config): Context {
},
UserPostQueries::class => function($c) {
return new UserPostQueries($c->get(\PDO::class));
- },
- IpNoteQueries::class => fn($c) => new IpNoteQueries($c->get(\PDO::class), $c->get(CacheDriver::class)),
+ }
]);
}
diff --git a/inc/filters.php b/inc/filters.php
index 97cbc524..2a66cd2a 100644
--- a/inc/filters.php
+++ b/inc/filters.php
@@ -4,26 +4,23 @@
* Copyright (c) 2010-2013 Tinyboard Development Group
*/
-use Vichan\Context;
-use Vichan\Data\IpNoteQueries;
-
defined('TINYBOARD') or exit;
class Filter {
public $flood_check;
private $condition;
private $post;
-
+
public function __construct(array $arr) {
foreach ($arr as $key => $value)
- $this->$key = $value;
+ $this->$key = $value;
}
-
+
public function match($condition, $match) {
$condition = strtolower($condition);
$post = &$this->post;
-
+
switch($condition) {
case 'custom':
if (!is_callable($match))
@@ -32,11 +29,11 @@ class Filter {
case 'flood-match':
if (!is_array($match))
error('Filter condition "flood-match" must be an array.');
-
+
// Filter out "flood" table entries which do not match this filter.
-
+
$flood_check_matched = array();
-
+
foreach ($this->flood_check as $flood_post) {
foreach ($match as $flood_match_arg) {
switch ($flood_match_arg) {
@@ -72,10 +69,10 @@ class Filter {
}
$flood_check_matched[] = $flood_post;
}
-
+
// is there any reason for this assignment?
$this->flood_check = $flood_check_matched;
-
+
return !empty($this->flood_check);
case 'flood-time':
foreach ($this->flood_check as $flood_post) {
@@ -138,42 +135,46 @@ class Filter {
error('Unknown filter condition: ' . $condition);
}
}
-
- public function action(Context $ctx) {
+
+ public function action() {
global $board;
$this->add_note = isset($this->add_note) ? $this->add_note : false;
if ($this->add_note) {
- $note_queries = $ctx->get(IpNoteQueries::class);
- $note_queries->add($_SERVER['REMOTE_ADDR'], -1, 'Autoban message: ' . $this->post['body']);
- }
+ $query = prepare('INSERT INTO ``ip_notes`` VALUES (NULL, :ip, :mod, :time, :body)');
+ $query->bindValue(':ip', $_SERVER['REMOTE_ADDR']);
+ $query->bindValue(':mod', -1);
+ $query->bindValue(':time', time());
+ $query->bindValue(':body', "Autoban message: ".$this->post['body']);
+ $query->execute() or error(db_error($query));
+ }
if (isset ($this->action)) switch($this->action) {
case 'reject':
error(isset($this->message) ? $this->message : 'Posting blocked by filter.');
case 'ban':
if (!isset($this->reason))
error('The ban action requires a reason.');
-
+
$this->expires = isset($this->expires) ? $this->expires : false;
$this->reject = isset($this->reject) ? $this->reject : true;
$this->all_boards = isset($this->all_boards) ? $this->all_boards : false;
-
+
Bans::new_ban($_SERVER['REMOTE_ADDR'], $this->reason, $this->expires, $this->all_boards ? false : $board['uri'], -1);
if ($this->reject) {
if (isset($this->message))
error($message);
-
+
checkBan($board['uri']);
exit;
}
-
+
break;
default:
error('Unknown filter action: ' . $this->action);
}
}
-
+
public function check(array $post) {
$this->post = $post;
foreach ($this->condition as $condition => $value) {
@@ -183,7 +184,7 @@ class Filter {
} else {
$NOT = false;
}
-
+
if ($this->match($condition, $value) == $NOT)
return false;
}
@@ -193,11 +194,11 @@ class Filter {
function purge_flood_table() {
global $config;
-
+
// Determine how long we need to keep a cache of posts for flood prevention. Unfortunately, it is not
// aware of flood filters in other board configurations. You can solve this problem by settings the
// config variable $config['flood_cache'] (seconds).
-
+
if (isset($config['flood_cache'])) {
$max_time = &$config['flood_cache'];
} else {
@@ -207,18 +208,18 @@ function purge_flood_table() {
$max_time = max($max_time, $filter['condition']['flood-time']);
}
}
-
+
$time = time() - $max_time;
-
+
query("DELETE FROM ``flood`` WHERE `time` < $time") or error(db_error());
}
-function do_filters(Context $ctx, array $post) {
+function do_filters(array $post) {
global $config;
if (!isset($config['filters']) || empty($config['filters']))
return;
-
+
foreach ($config['filters'] as $filter) {
if (isset($filter['condition']['flood-match'])) {
$has_flood = true;
@@ -231,15 +232,15 @@ function do_filters(Context $ctx, array $post) {
} else {
$flood_check = false;
}
-
+
foreach ($config['filters'] as $filter_array) {
$filter = new Filter($filter_array);
$filter->flood_check = $flood_check;
if ($filter->check($post)) {
- $filter->action($ctx);
+ $filter->action();
}
}
-
+
purge_flood_table();
}
diff --git a/inc/functions.php b/inc/functions.php
index def00287..66cd6fa7 100644
--- a/inc/functions.php
+++ b/inc/functions.php
@@ -2069,7 +2069,7 @@ function remove_modifiers($body) {
return preg_replace('@>>$cite";
- }
- $body = mb_substr_replace($body, $matches[1][0] . $replacement . $matches[3][0], $matches[0][1] + $skip_chars, mb_strlen($matches[0][0]));
- $skip_chars += mb_strlen($matches[1][0] . $replacement . $matches[3][0]) - mb_strlen($matches[0][0]);
+ $body = mb_substr_replace($body, $matches[1][0] . $replacement . $matches[3][0], $matches[0][1] + $skip_chars, mb_strlen($matches[0][0]));
+ $skip_chars += mb_strlen($matches[1][0] . $replacement . $matches[3][0]) - mb_strlen($matches[0][0]);
- if ($track_cites && $config['track_cites']) {
- $tracked_cites[] = array($board['uri'], $cite);
+ if ($track_cites && $config['track_cites'])
+ $tracked_cites[] = array($board['uri'], $cite);
}
}
}
diff --git a/inc/mod/pages.php b/inc/mod/pages.php
index 155c19a6..380a5627 100644
--- a/inc/mod/pages.php
+++ b/inc/mod/pages.php
@@ -3,20 +3,17 @@
* Copyright (c) 2010-2013 Tinyboard Development Group
*/
use Vichan\Context;
-use Vichan\Data\{IpNoteQueries, UserPostQueries, ReportQueries};
-use Vichan\Data\Driver\LogDriver;
+use Vichan\Data\{UserPostQueries, ReportQueries};
use Vichan\Functions\Net;
defined('TINYBOARD') or exit;
-function _link_or_copy_factory(Context $ctx): callable {
- return function(string $target, string $link) use ($ctx) {
- if (!\link($target, $link)) {
- $ctx->get(LogDriver::class)->log(LogDriver::NOTICE, "Failed to link() $target to $link. FAlling back to copy()");
- return \copy($target, $link);
- }
- return true;
- };
+function _link_or_copy(string $target, string $link): bool {
+ if (!link($target, $link)) {
+ error_log("Failed to link() $target to $link. FAlling back to copy()");
+ return copy($target, $link);
+ }
+ return true;
}
function mod_page($title, $template, $args, $subtitle = false) {
@@ -57,7 +54,8 @@ function mod_login(Context $ctx, $redirect = false) {
if (!isset($_POST['username'], $_POST['password']) || $_POST['username'] == '' || $_POST['password'] == '') {
$args['error'] = $config['error']['invalid'];
} elseif (!login($_POST['username'], $_POST['password'])) {
- $ctx->get(LogDriver::class)->log(LogDriver::INFO, 'Unauthorized login attempt!');
+ if ($config['syslog'])
+ _syslog(LOG_WARNING, 'Unauthorized login attempt!');
$args['error'] = $config['error']['invalid'];
} else {
@@ -853,26 +851,18 @@ function mod_view_thread50(Context $ctx, $boardName, $thread) {
}
function mod_ip_remove_note(Context $ctx, $ip, $id) {
- $config = $ctx->get('config');
+ global $config;
- if (!hasPermission($config['mod']['remove_notes'])) {
- error($config['error']['noaccess']);
- }
+ if (!hasPermission($config['mod']['remove_notes']))
+ error($config['error']['noaccess']);
- if (filter_var($ip, \FILTER_VALIDATE_IP) === false) {
+ if (filter_var($ip, FILTER_VALIDATE_IP) === false)
error('Invalid IP address');
- }
- if (!is_numeric($id)) {
- error('Invalid note ID');
- }
-
- $queries = $ctx->get(IpNoteQueries::class);
- $deleted = $queries->deleteWhereIp((int)$id, $ip);
-
- if (!$deleted) {
- error("Note $id does not exist for $ip");
- }
+ $query = prepare('DELETE FROM ``ip_notes`` WHERE `ip` = :ip AND `id` = :id');
+ $query->bindValue(':ip', $ip);
+ $query->bindValue(':id', $id);
+ $query->execute() or error(db_error($query));
modLog("Removed a note for {$ip}");
@@ -880,17 +870,14 @@ function mod_ip_remove_note(Context $ctx, $ip, $id) {
}
function mod_ip(Context $ctx, $ip, string $encoded_cursor = null) {
- global $mod;
- $config = $ctx->get('config');
+ global $config, $mod;
- if (filter_var($ip, FILTER_VALIDATE_IP) === false) {
+ if (filter_var($ip, FILTER_VALIDATE_IP) === false)
error('Invalid IP address');
- }
if (isset($_POST['ban_id'], $_POST['unban'])) {
- if (!hasPermission($config['mod']['unban'])) {
+ if (!hasPermission($config['mod']['unban']))
error($config['error']['noaccess']);
- }
Bans::delete($_POST['ban_id'], true, $mod['boards']);
@@ -903,15 +890,17 @@ function mod_ip(Context $ctx, $ip, string $encoded_cursor = null) {
}
if (isset($_POST['note'])) {
- if (!hasPermission($config['mod']['create_notes'])) {
+ if (!hasPermission($config['mod']['create_notes']))
error($config['error']['noaccess']);
- }
$_POST['note'] = escape_markup_modifiers($_POST['note']);
markup($_POST['note']);
-
- $note_queries = $ctx->get(IpNoteQueries::class);
- $note_queries->add($ip, $mod['id'], $_POST['note']);
+ $query = prepare('INSERT INTO ``ip_notes`` VALUES (NULL, :ip, :mod, :time, :body)');
+ $query->bindValue(':ip', $ip);
+ $query->bindValue(':mod', $mod['id']);
+ $query->bindValue(':time', time());
+ $query->bindValue(':body', $_POST['note']);
+ $query->execute() or error(db_error($query));
Cache::delete("mod_page_ip_view_notes_$ip");
@@ -963,8 +952,15 @@ function mod_user_posts_by_ip(Context $ctx, string $ip, string $encoded_cursor =
}
if (hasPermission($config['mod']['view_notes'])) {
- $note_queries = $ctx->get(IpNoteQueries::class);
- $args['notes'] = $note_queries->getByIp($ip);
+ $ret = Cache::get("mod_page_ip_view_notes_$ip");
+ if (!$ret) {
+ $query = prepare("SELECT ``ip_notes``.*, `username` FROM ``ip_notes`` LEFT JOIN ``mods`` ON `mod` = ``mods``.`id` WHERE `ip` = :ip ORDER BY `time` DESC");
+ $query->bindValue(':ip', $ip);
+ $query->execute() or error(db_error($query));
+ $ret = $query->fetchAll(PDO::FETCH_ASSOC);
+ Cache::set("mod_page_ip_view_notes_$ip", $ret, 900);
+ }
+ $args['notes'] = $ret;
}
if (hasPermission($config['mod']['modlog_ip'])) {
@@ -1091,6 +1087,12 @@ function mod_user_posts_by_passwd(Context $ctx, string $passwd, string $encoded_
$args['boards'] = $boards;
$args['token'] = make_secure_link_token('ban');
+ if (empty($encoded_cursor)) {
+ $args['security_token'] = make_secure_link_token("user_posts/passwd/$passwd");
+ } else {
+ $args['security_token'] = make_secure_link_token("user_posts/passwd/$passwd/cursor/$encoded_cursor");
+ }
+
mod_page(\sprintf('%s: %s', _('Password'), \htmlspecialchars($passwd)), 'mod/view_passwd.html', $args);
}
@@ -1491,9 +1493,8 @@ function mod_move(Context $ctx, $originBoard, $postID) {
if ($targetBoard === $originBoard)
error(_('Target and source board are the same.'));
- $_link_or_copy = _link_or_copy_factory($ctx);
// link() if leaving a shadow thread behind; else, rename().
- $clone = $shadow ? $_link_or_copy : 'rename';
+ $clone = $shadow ? '_link_or_copy' : 'rename';
// indicate that the post is a thread
$post['op'] = true;
@@ -1787,8 +1788,7 @@ function mod_merge(Context $ctx, $originBoard, $postID) {
$op = $post;
$op['id'] = $newID;
- $_link_or_copy = _link_or_copy_factory($ctx);
- $clone = $shadow ? $_link_or_copy : 'rename';
+ $clone = $shadow ? '_link_or_copy' : 'rename';
if ($post['has_file']) {
// copy image
@@ -2004,9 +2004,13 @@ function mod_ban_post(Context $ctx, $board, $delete, $post, $token = false) {
$autotag .= "/${board}/" . " " . $filehash . " " . $filename ."\r\n";
$autotag .= $body . "\r\n";
$autotag = escape_markup_modifiers($autotag);
-
- $note_queries = $ctx->get(IpNoteQueries::class);
- $note_queries->add($ip, $mod['id'], $autotag);
+ markup($autotag);
+ $query = prepare('INSERT INTO ``ip_notes`` VALUES (NULL, :ip, :mod, :time, :body)');
+ $query->bindValue(':ip', $ip);
+ $query->bindValue(':mod', $mod['id']);
+ $query->bindValue(':time', time());
+ $query->bindValue(':body', $autotag);
+ $query->execute() or error(db_error($query));
modLog("Added a note for {$ip}");
}
}
@@ -2112,9 +2116,12 @@ function mod_warning_post(Context $ctx, $board, $post, $token = false) {
$autotag .= $body . "\r\n";
$autotag = escape_markup_modifiers($autotag);
markup($autotag);
-
- $note_queries = $ctx->get(IpNoteQueries::class);
- $note_queries->add($ip, $mod['id'], $autotag);
+ $query = prepare('INSERT INTO ``ip_notes`` VALUES (NULL, :ip, :mod, :time, :body)');
+ $query->bindValue(':ip', $ip);
+ $query->bindValue(':mod', $mod['id']);
+ $query->bindValue(':time', time());
+ $query->bindValue(':body', $autotag);
+ $query->execute() or error(db_error($query));
modLog("Added a note for {$ip}");
}
}
@@ -2220,7 +2227,7 @@ function mod_edit_post(Context $ctx, $board, $edit_raw_html, $postID) {
}
function mod_delete(Context $ctx, $board, $post) {
- global $config, $mod;
+ global $config;
if (!openBoard($board))
error($config['error']['noboard']);
@@ -2261,9 +2268,12 @@ function mod_delete(Context $ctx, $board, $post) {
$autotag .= $body . "\r\n";
$autotag = escape_markup_modifiers($autotag);
markup($autotag);
-
- $note_queries = $ctx->get(IpNoteQueries::class);
- $note_queries->add($ip, $mod['id'], $autotag);
+ $query = prepare('INSERT INTO ``ip_notes`` VALUES (NULL, :ip, :mod, :time, :body)');
+ $query->bindValue(':ip', $ip);
+ $query->bindValue(':mod', $mod['id']);
+ $query->bindValue(':time', time());
+ $query->bindValue(':body', $autotag);
+ $query->execute() or error(db_error($query));
modLog("Added a note for {$ip}");
}
}
@@ -2351,7 +2361,7 @@ function mod_spoiler_image(Context $ctx, $board, $post, $file) {
}
function mod_deletebyip(Context $ctx, $boardName, $post, $global = false) {
- global $config, $board, $mod;
+ global $config, $board;
$global = (bool)$global;
@@ -2429,9 +2439,12 @@ function mod_deletebyip(Context $ctx, $boardName, $post, $global = false) {
$autotag .= $body . "\r\n";
$autotag = escape_markup_modifiers($autotag);
markup($autotag);
-
- $note_queries = $ctx->get(IpNoteQueries::class);
- $note_queries->add($ip, $mod['id'], $autotag);
+ $query2 = prepare('INSERT INTO ``ip_notes`` VALUES (NULL, :ip, :mod, :time, :body)');
+ $query2->bindValue(':ip', $ip);
+ $query2->bindValue(':mod', $mod['id']);
+ $query2->bindValue(':time', time());
+ $query2->bindValue(':body', $autotag);
+ $query2->execute() or error(db_error($query2));
modLog("Added a note for {$ip}");
}
}
diff --git a/js/ajax.js b/js/ajax.js
index 3cb06bf1..f65c6c96 100644
--- a/js/ajax.js
+++ b/js/ajax.js
@@ -111,7 +111,7 @@ $(window).ready(function() {
$(form).find('input[type="submit"]').val(submit_txt);
$(form).find('input[type="submit"]').removeAttr('disabled');
$(form).find('input[name="subject"],input[name="file_url"],\
- textarea[name="body"],input[type="file"],input[name="embed"]').val('').change();
+ textarea[name="body"],input[type="file"]').val('').change();
},
cache: false,
contentType: false,
@@ -123,7 +123,7 @@ $(window).ready(function() {
$(form).find('input[type="submit"]').val(submit_txt);
$(form).find('input[type="submit"]').removeAttr('disabled');
$(form).find('input[name="subject"],input[name="file_url"],\
- textarea[name="body"],input[type="file"],input[name="embed"]').val('').change();
+ textarea[name="body"],input[type="file"]').val('').change();
} else {
alert(_('An unknown error occured when posting!'));
$(form).find('input[type="submit"]').val(submit_txt);
diff --git a/js/inline-expanding.js b/js/inline-expanding.js
index c44843b0..41625d2d 100644
--- a/js/inline-expanding.js
+++ b/js/inline-expanding.js
@@ -17,10 +17,6 @@ $(document).ready(function() {
// Default maximum image loads.
const DEFAULT_MAX = 5;
- if (localStorage.inline_expand_fit_height !== 'false') {
- $('').appendTo($('head'));
- }
-
let inline_expand_post = function() {
let link = this.getElementsByTagName('a');
@@ -60,12 +56,12 @@ $(document).ready(function() {
},
add: function(ele) {
ele.deferred = $.Deferred();
- ele.deferred.done(function() {
+ ele.deferred.done(function () {
let $loadstart = $.Deferred();
let thumb = ele.childNodes[0];
let img = ele.childNodes[1];
- let onLoadStart = function(img) {
+ let onLoadStart = function (img) {
if (img.naturalWidth) {
$loadstart.resolve(img, thumb);
} else {
@@ -73,15 +69,15 @@ $(document).ready(function() {
}
};
- $(img).one('load', function() {
- $.when($loadstart).done(function() {
- // once fully loaded, update the waiting queue
+ $(img).one('load', function () {
+ $.when($loadstart).done(function () {
+ // Once fully loaded, update the waiting queue.
--loading;
$(ele).data('imageLoading', 'false');
update();
});
});
- $loadstart.done(function(img, thumb) {
+ $loadstart.done(function (img, thumb) {
thumb.style.display = 'none';
img.style.display = '';
});
@@ -206,8 +202,6 @@ $(document).ready(function() {
Options.extend_tab('general', '' +
_('Number of simultaneous image downloads (0 to disable): ') +
'');
- Options.extend_tab('general', '');
-
$('#inline-expand-max input')
.css('width', '50px')
.val(localStorage.inline_expand_max || DEFAULT_MAX)
@@ -218,21 +212,6 @@ $(document).ready(function() {
localStorage.inline_expand_max = val;
});
-
- $('#inline-expand-fit-height input').on('change', function() {
- if (localStorage.inline_expand_fit_height !== 'false') {
- localStorage.inline_expand_fit_height = 'false';
- $('#expand-fit-height-style').remove();
- }
- else {
- localStorage.inline_expand_fit_height = 'true';
- $('').appendTo($('head'));
- }
- });
-
- if (localStorage.inline_expand_fit_height !== 'false') {
- $('#inline-expand-fit-height input').prop('checked', true);
- }
}
if (window.jQuery) {
diff --git a/js/options/fav.js b/js/options/fav.js
index 17ccb337..3236e70e 100644
--- a/js/options/fav.js
+++ b/js/options/fav.js
@@ -23,20 +23,20 @@ function addBoard(){
add_favorites();
} //This adds the text inside the textbox to favorites, localStorage.favorites and the page
-var favorites = JSON.parse(localStorage.favorites);
+var favorites = localStorage.favorites ? JSON.parse(localStorage.favorites) : [];
Options.add_tab('fav-tab','star',_("Favorites"));
-//Pregenerating list of boards
+//Pregenerating list of boards
var favList = $('
GLOBAL:
@@ -36,7 +36,7 @@ Opening posts with liberalism or reactionary topics will be treated with far mor9) Due to derailing, COVID denialism outside the COVID-19 thread will be deleted.
-10) All boards except for /siberia/ (and potentially /roulette/) are 'Safe For Work' boards. Pornography should not be posted on them without good reason, and any pornography on these boards should be hidden using the Spoiler Image option. New threads on /siberia/ with pornographic topics should have a Spoiler Image on the opening post. Some kinds of pornographic content are always banned on every board, including /siberia/: cp/loli/jailbait/anything that could possibly interpreted a child, "feral" furry, zoophilia, murder/gore (photographic) and other suitably extreme fetishes.
+10) All boards except for /siberia/ (and potentially /roulette/) are 'Safe For Work' boards. Pornography should not be posted on them without good reason, and any pornography on these boards should be hidden using the Spoiler Image option. New threads on /siberia/ with pornographic topics should have a Spoiler Image on the opening post.
11) Posts should, overall, be conductive to an informed and productive discussion. /leftypol/ is not an academic journal, but it also should not be a cesspit of back and forth bickering and pointless insults. Users should attempt to argue for the point they are presenting in an honest and open way and should be receptive to information or arguments that do, in fact, challenge their views.
diff --git a/templates/themes/categories/frames.html b/templates/themes/categories/frames.html index 1c4673cc..6b2fac38 100644 --- a/templates/themes/categories/frames.html +++ b/templates/themes/categories/frames.html @@ -16,13 +16,13 @@ border-width: 2px; margin-right: 15px; } - + .introduction { grid-column: 2 / 9; grid-row: 1; width: 100%; } - + .content { grid-column: 2 / 9; grid-row: 2; @@ -35,7 +35,7 @@ gap: 20px; height: 100vh; } - + .modlog { width: 50%; text-align: left; @@ -69,7 +69,7 @@ li a.system { font-weight: bold; } - + @media (max-width:768px) { body{ display: grid; @@ -78,7 +78,7 @@ height: 100vh; width: 100%; } - + .introduction { grid-column: 1; grid-row: 1; @@ -96,18 +96,17 @@ grid-column: 1; grid-row: 3; width: 100%; - word-break: break-all; } - + .modlog { width: 100%; text-align: center; } - + table { table-layout: fixed; } - + table.modlog tr th { white-space: normal; word-wrap: break-word; diff --git a/templates/themes/categories/news.html b/templates/themes/categories/news.html index 76722e41..484c4eb0 100644 --- a/templates/themes/categories/news.html +++ b/templates/themes/categories/news.html @@ -11,7 +11,7 @@ .home-description { margin: 20px auto 0 auto; text-align: center; - max-width: 700px; + max-width: 700px;" } {{ boardlist.top }} diff --git a/templates/themes/faq/index.html b/templates/themes/faq/index.html index b63a4483..6ddf872a 100644 --- a/templates/themes/faq/index.html +++ b/templates/themes/faq/index.html @@ -88,7 +88,7 @@There is a /meta/ thread for this, and our Forgejo repo.
+There is a /meta/ thread for this, and our Gitlab repo.
Maximum file size in megabytes for attachments to a single post is 80MB (e.g. 5 * 16MB), as most boards support uploading 5 attachments by default. Maximum file size in pixels for images is currently set to 20000 by 20000.
-Create the account on Forgejo, then contact the staff via the Tech Team General thread on /meta/ to get your account approved.