This commit is contained in:
8n-tech 2015-05-14 11:05:49 +10:00
commit 3c9c1e5e35
27 changed files with 379 additions and 96 deletions

View File

@ -21,6 +21,7 @@ $title = $_POST['title'];
$subtitle = $_POST['subtitle'];
$username = $_POST['username'];
$password = $_POST['password'];
$email = (isset($_POST['email']) ? $_POST['email'] : '');
$resp = file_get_contents($config['captcha']['provider_check'] . "?" . http_build_query([
'mode' => 'check',
@ -39,6 +40,8 @@ if (!preg_match('/^[a-zA-Z0-9._]{1,30}$/', $username))
error(_('Invalid username'));
if ($resp !== '1')
error($config['error']['captcha']);
if (!filter_var($email, FILTER_VALIDATE_EMAIL))
$email = '';
foreach (listBoards() as $i => $board) {
if ($board['uri'] == $uri)
@ -66,12 +69,13 @@ error(_('The username you\'ve tried to enter already exists!'));
$salt = generate_salt();
$password = hash('sha256', $salt . sha1($password));
$query = prepare('INSERT INTO ``mods`` VALUES (NULL, :username, :password, :salt, :type, :boards)');
$query = prepare('INSERT INTO ``mods`` VALUES (NULL, :username, :password, :salt, :type, :boards, :email)');
$query->bindValue(':username', $username);
$query->bindValue(':password', $password);
$query->bindValue(':salt', $salt);
$query->bindValue(':type', 20);
$query->bindValue(':boards', $uri);
$query->bindValue(':email', $email);
$query->execute() or error(db_error($query));
$query = prepare('INSERT INTO ``boards`` (`uri`, `title`, `subtitle`) VALUES (:uri, :title, :subtitle)');

View File

@ -15,6 +15,7 @@
$config['mod']['mod_board_log'] = MOD;
$config['mod']['editpost'] = BOARDVOLUNTEER;
$config['mod']['edit_banners'] = MOD;
$config['mod']['edit_assets'] = MOD;
$config['mod']['edit_flags'] = MOD;
$config['mod']['edit_settings'] = MOD;
$config['mod']['edit_volunteers'] = MOD;
@ -51,3 +52,4 @@
$config['mod']['custom_pages']['/flags/(\%b)'] = '8_flags';
$config['mod']['custom_pages']['/banners/(\%b)'] = '8_banners';
$config['mod']['custom_pages']['/settings/(\%b)'] = '8_settings';
$config['mod']['custom_pages']['/assets/(\%b)'] = '8_assets';

View File

@ -118,7 +118,7 @@
$salt = generate_salt();
$password = hash('sha256', $salt . sha1($_POST['password']));
$query = prepare('INSERT INTO ``mods`` VALUES (NULL, :username, :password, :salt, 19, :board)');
$query = prepare('INSERT INTO ``mods`` VALUES (NULL, :username, :password, :salt, 19, :board, "")');
$query->bindValue(':username', $_POST['username']);
$query->bindValue(':password', $password);
$query->bindValue(':salt', $salt);
@ -224,7 +224,7 @@
}
copy($upload, "$dir/$id.$extension");
purge("$dir/$id.$extension");
purge("$dir/$id.$extension", true);
$config['user_flags'][$id] = utf8tohtml($description);
file_write($b.'/flags.ser', serialize($config['user_flags']));
}
@ -303,6 +303,120 @@ FLAGS;
mod_page(_('Edit flags'), 'mod/flags.html', array('board'=>$board,'banners'=>$banners,'token'=>make_secure_link_token('banners/'.$board['uri'])));
}
function mod_8_assets($b) {
global $config, $mod, $board;
require_once 'inc/image.php';
if (!hasPermission($config['mod']['edit_assets'], $b))
error($config['error']['noaccess']);
if (!openBoard($b))
error("Could not open board!");
$dir = 'static/assets/'.$b;
if (!is_dir($dir)){
mkdir($dir, 0777, true);
symlink(getcwd() . '/' . $config['image_deleted'], "$dir/deleted.png");
symlink(getcwd() . '/' . $config['spoiler_image'], "$dir/spoiler.png");
symlink(getcwd() . '/' . $config['no_file_image'], "$dir/no-file.png");
}
// "File deleted"
if (isset($_FILES['deleted_file']) && !empty($_FILES['deleted_file']['tmp_name'])){
$upload = $_FILES['deleted_file']['tmp_name'];
$extension = strtolower(mb_substr($_FILES['deleted_file']['name'], mb_strrpos($_FILES['deleted_file']['name'], '.') + 1));
if (!is_readable($upload)) {
error($config['error']['nomove']);
}
if (filesize($upload) > 512000){
error('File too large!');
}
if (!in_array($extension, array('png', 'gif'))) {
error('File must be PNG or GIF format.');
}
if (!$size = @getimagesize($upload)) {
error($config['error']['invalidimg']);
}
if ($size[0] != 140 or $size[1] != 50){
error('Image wrong size!');
}
unlink("$dir/deleted.png");
copy($upload, "$dir/deleted.png");
purge("$dir/deleted.png", true);
}
// Spoiler file
if (isset($_FILES['spoiler_file']) && !empty($_FILES['spoiler_file']['tmp_name'])){
$upload = $_FILES['spoiler_file']['tmp_name'];
$extension = strtolower(mb_substr($_FILES['spoiler_file']['name'], mb_strrpos($_FILES['spoiler_file']['name'], '.') + 1));
if (!is_readable($upload)) {
error($config['error']['nomove']);
}
if (filesize($upload) > 512000){
error('File too large!');
}
if (!in_array($extension, array('png', 'gif'))) {
error('File must be PNG or GIF format.');
}
if (!$size = @getimagesize($upload)) {
error($config['error']['invalidimg']);
}
if ($size[0] != 128 or $size[1] != 128){
error('Image wrong size!');
}
unlink("$dir/spoiler.png");
copy($upload, "$dir/spoiler.png");
purge("$dir/spoiler.png", true);
}
// No file
if (isset($_FILES['nofile_file']) && !empty($_FILES['nofile_file']['tmp_name'])){
$upload = $_FILES['nofile_file']['tmp_name'];
$extension = strtolower(mb_substr($_FILES['nofile_file']['name'], mb_strrpos($_FILES['nofile_file']['name'], '.') + 1));
if (!is_readable($upload)) {
error($config['error']['nomove']);
}
if (filesize($upload) > 512000){
error('File too large!');
}
if (!in_array($extension, array('png', 'gif'))) {
error('File must be PNG or GIF format.');
}
if (!$size = @getimagesize($upload)) {
error($config['error']['invalidimg']);
}
if ($size[0] != 500 or $size[1] != 500){
error('Image wrong size!');
}
unlink("$dir/no-file.png");
copy($upload, "$dir/no-file.png");
purge("$dir/no-file.png", true);
}
mod_page(_('Edit board assets'), 'mod/assets.html', array('board'=>$board,'token'=>make_secure_link_token('assets/'.$board['uri'])));
}
function mod_8_banners($b) {
global $config, $mod, $board;
require_once 'inc/image.php';
@ -431,6 +545,16 @@ FLAGS;
$multiimage = '';
}
if (isset($_POST['custom_assets'])) {
$assets = "\$config['custom_assets'] = true;
\$config['spoiler_image'] = 'static/assets/$b/spoiler.png';
\$config['image_deleted'] = 'static/assets/$b/deleted.png';
\$config['no_file_image'] = 'static/assets/$b/no-file.png';
";
} else {
$assets = '';
}
$file_board = '';
if ($fileboard) {
$force_image_op = true;
@ -475,7 +599,7 @@ FLAGS;
}
}
$anal_filenames = ($imgboard || $fileboard) && isset($_POST['anal_filenames']) ? "\$config['filename_func'] = 'filename_func';\n" : '';
$anal_filenames = ($fileboard) && isset($_POST['anal_filenames']) ? "\$config['filename_func'] = 'filename_func';\n" : '';
$anonymous = base64_encode($_POST['anonymous']);
$blotter = base64_encode(purify_html(html_entity_decode($_POST['blotter'])));
@ -588,7 +712,8 @@ FLAGS;
\$config['max_pages'] = $max_pages;
\$config['max_newlines'] = $max_newlines;
\$config['oekaki'] = $oekaki;
$code_tags $katex $replace $multiimage $allow_flash $allow_pdf $user_flags
$code_tags $katex $replace $multiimage $allow_flash $allow_pdf $user_flags
$assets
$locale
$anal_filenames
$file_board

View File

@ -92,7 +92,7 @@ class Api {
$apiPost['filename'] = @substr($file->name, 0, strrpos($file->name, '.'));
$dotPos = strrpos($file->file, '.');
$apiPost['ext'] = substr($file->file, $dotPos);
$apiPost['tim'] = substr($file->file, 0, $dotPos);
$apiPost['tim'] = urlencode(substr($file->file, 0, $dotPos));
if (isset($file->hash))
$apiPost['md5'] = base64_encode(hex2bin($file->hash));
}

View File

@ -187,7 +187,9 @@ class Bans {
if ($ban['post']) {
$post = json_decode($ban['post']);
$ban['message'] = $post->body;
if ($post) {
$ban['message'] = $post->body;
}
}
unset($ban['ipstart'], $ban['ipend'], $ban['post'], $ban['creator']);

View File

@ -839,7 +839,7 @@
// Location of thumbnail to use for spoiler images.
$config['spoiler_image'] = 'static/spoiler.png';
// Location of thumbnail to use for deleted images.
// $config['image_deleted'] = 'static/deleted.png';
$config['image_deleted'] = 'static/deleted.png';
// Location of placeholder image for fileless posts in catalog.
$config['no_file_image'] = 'static/no-file.png';
@ -1530,7 +1530,7 @@
// Edit any users' login information
$config['mod']['editusers'] = ADMIN;
// Change user's own password
$config['mod']['change_password'] = JANITOR;
$config['mod']['edit_profile'] = JANITOR;
// Delete a user
$config['mod']['deleteusers'] = ADMIN;
// Create a user
@ -1783,4 +1783,14 @@
$config['report_captcha'] = false;
// Allowed HTML tags in ?/edit_pages.
$config['allowed_html'] = 'a[href|title],p,br,li,ol,ul,strong,em,u,h2,b,i,tt,div,img[src|alt|title],hr';
$config['allowed_html'] = 'a[href|title],p,br,li,ol,ul,strong,em,u,h2,b,i,tt,div,img[src|alt|title],hr,h1,h2,h3,h4,h5';
// Use custom assets? (spoiler file, etc; this is used by ?/settings and ?/assets)
$config['custom_assets'] = false;
// If you use CloudFlare set these for some features to work correctly.
$config['cloudflare'] = array();
$config['cloudflare']['enabled'] = false;
$config['cloudflare']['token'] = 'token';
$config['cloudflare']['email'] = 'email';
$config['cloudflare']['domain'] = 'example.com';

View File

@ -589,9 +589,42 @@ function boardTitle($uri) {
return false;
}
function purge($uri) {
function cloudflare_purge($uri) {
global $config;
if (!$config['cloudflare']['enabled']) return;
$fields = array(
'a' => 'zone_file_purge',
'tkn' => $config['cloudflare']['token'],
'email' => $config['cloudflare']['email'],
'z' => $config['cloudflare']['domain'],
'url' => 'https://' . $config['cloudflare']['domain'] . '/' . $uri
);
$fields_string = http_build_query($fields);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://www.cloudflare.com/api_json.html');
curl_setopt($ch, CURLOPT_POST, count($fields));
curl_setopt($ch, CURLOPT_POSTFIELDS, $fields_string);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$result = curl_exec($ch);
curl_close($ch);
return $result;
}
function purge($uri, $cloudflare = false) {
global $config, $debug;
if ($cloudflare) {
cloudflare_purge($uri);
}
if (!isset($config['purge'])) return;
// Fix for Unicode
@ -986,7 +1019,7 @@ function fetchBoardTags( $uris ) {
$boardTags[ $tagRow['uri'] ] = array();
}
$boardTags[ $tagRow['uri'] ][] = htmlentities( utf8_encode( $tag ) );
$boardTags[ $tagRow['uri'] ][] = $tag;
}
}

View File

@ -57,17 +57,17 @@ function make_webm_thumbnail($filename, $thumbnail, $width, $height, $duration)
global $board, $config;
$filename = escapeshellarg($filename);
//$thumbnail = escapeshellarg($thumbnail); // Should be safe by default but you
$thumbnailfc = escapeshellarg($thumbnail); // Should be safe by default but you
// can never be too safe.
$ffmpeg = $config['webm']['ffmpeg_path'];
$ret = 0;
$ffmpeg_out = array();
exec("$ffmpeg -strict -2 -ss " . floor($duration / 2) . " -i $filename -v quiet -an -vframes 1 -f mjpeg -vf scale=$width:$height $thumbnail 2>&1", $ffmpeg_out, $ret);
exec("$ffmpeg -strict -2 -ss " . floor($duration / 2) . " -i $filename -v quiet -an -vframes 1 -f mjpeg -vf scale=$width:$height $thumbnailfc 2>&1", $ffmpeg_out, $ret);
// Work around for https://trac.ffmpeg.org/ticket/4362
if (filesize($thumbnail) === 0) {
// try again with first frame
exec("$ffmpeg -y -strict -2 -ss 0 -i $filename -v quiet -an -vframes 1 -f mjpeg -vf scale=$width:$height $thumbnail 2>&1", $ffmpeg_out, $ret);
exec("$ffmpeg -y -strict -2 -ss 0 -i $filename -v quiet -an -vframes 1 -f mjpeg -vf scale=$width:$height $thumbnailfc 2>&1", $ffmpeg_out, $ret);
clearstatcache();
// failed if no thumbnail size even if ret code 0, ffmpeg is buggy
if (filesize($thumbnail) === 0) {

View File

@ -1914,11 +1914,11 @@ function mod_deletebyip($boardName, $post, $global = false) {
function mod_user($uid) {
global $config, $mod;
if (!hasPermission($config['mod']['editusers']) && !(hasPermission($config['mod']['change_password']) && $uid == $mod['id']))
if (!hasPermission($config['mod']['editusers']) && !(hasPermission($config['mod']['edit_profile']) && $uid == $mod['id']))
error($config['error']['noaccess']);
if (in_array($mod['boards'][0], array('infinity', 'z')))
error('This board has password changing disabled.');
error('This board has profile changing disabled.');
$query = prepare('SELECT * FROM ``mods`` WHERE `id` = :id');
$query->bindValue(':id', $uid);
@ -1997,8 +1997,8 @@ function mod_user($uid) {
return;
}
if (hasPermission($config['mod']['change_password']) && $uid == $mod['id'] && isset($_POST['password'])) {
if ($_POST['password'] != '') {
if (hasPermission($config['mod']['edit_profile']) && $uid == $mod['id']) {
if (isset($_POST['password']) && $_POST['password'] != '') {
$salt = generate_salt();
$password = hash('sha256', $salt . sha1($_POST['password']));
@ -2013,13 +2013,50 @@ function mod_user($uid) {
login($user['username'], $_POST['password']);
setCookies();
}
if (isset($_POST['username']) && $user['username'] !== $_POST['username']) {
if ($_POST['username'] == '')
error(sprintf($config['error']['required'], 'username'));
if (!preg_match('/^[a-zA-Z0-9._]{1,30}$/', $_POST['username']))
error(_('Invalid username'));
$query = prepare('SELECT `username` FROM ``mods``');
$query->execute() or error(db_error($query));
$users = $query->fetchAll(PDO::FETCH_ASSOC);
foreach ($users as $i => $v) {
if (strtolower($_POST['username']) == strtolower($v['username'])) {
error(_('Refusing to change your username because another user is already using it.'));
}
}
$query = prepare('UPDATE ``mods`` SET `username` = :username WHERE `id` = :id');
$query->bindValue(':id', $uid);
$query->bindValue(':username', $_POST['username']);
$query->execute() or error(db_error($query));
if (hasPermission($config['mod']['manageusers']))
header('Location: ?/users', true, $config['redirect_http']);
else
header('Location: ?/', true, $config['redirect_http']);
modLog('Renamed user "' . utf8tohtml($user['username']) . '" <small>(#' . $user['id'] . ')</small> to "' . utf8tohtml($_POST['username']) . '"');
}
if (isset($_POST['email']) && $user['email'] !== $_POST['email'] && (empty($_POST['email']) || filter_var($_POST['email'], FILTER_VALIDATE_EMAIL))) {
// account was renamed
$query = prepare('UPDATE ``mods`` SET `email` = :email WHERE `id` = :id');
$query->bindValue(':id', $uid);
$query->bindValue(':email', $_POST['email']);
$query->execute() or error(db_error($query));
return;
modLog('Changed user\'s email "' . utf8tohtml($user['email']) . '" <small>(#' . $user['id'] . ')</small> to "' . utf8tohtml($_POST['email']) . '"');
}
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
if (hasPermission($config['mod']['manageusers']))
header('Location: ?/users', true, $config['redirect_http']);
else
header('Location: ?/', true, $config['redirect_http']);
return;
}
}
if (hasPermission($config['mod']['modlog'])) {
@ -2032,21 +2069,18 @@ function mod_user($uid) {
}
if ($mod['type'] >= ADMIN){
$boards = listBoards();
$boards = listBoards();
} else {
$boards2 = explode(',', $user['boards']);
foreach($boards2 as $string){
$boards[] = array("uri"=>$string, "title"=>"MY BOARD");
}
$boards2 = explode(',', $user['boards']);
foreach ($boards2 as $string){
$boards[] = array("uri"=>$string, "title" => _("My board"));
}
}
$user['boards'] = explode(',', $user['boards']);
mod_page(_('Edit user'), 'mod/user.html', array(
mod_page(_('Edit user profile'), 'mod/user.html', array(
'user' => $user,
'logs' => $log,
'boards' => $boards,
@ -2088,12 +2122,13 @@ function mod_user_new() {
$salt = generate_salt();
$password = hash('sha256', $salt . sha1($_POST['password']));
$query = prepare('INSERT INTO ``mods`` VALUES (NULL, :username, :password, :salt, :type, :boards)');
$query = prepare('INSERT INTO ``mods`` VALUES (NULL, :username, :password, :salt, :type, :boards, :email)');
$query->bindValue(':username', $_POST['username']);
$query->bindValue(':password', $password);
$query->bindValue(':salt', $salt);
$query->bindValue(':type', $type);
$query->bindValue(':boards', implode(',', $boards));
$query->bindValue(':email', (isset($_POST['email']) ? $_POST['email'] : ''));
$query->execute() or error(db_error($query));
$userID = $pdo->lastInsertId();
@ -2114,7 +2149,7 @@ function mod_users() {
if (!hasPermission($config['mod']['manageusers']))
error($config['error']['noaccess']);
$query = query("SELECT ``m``.`id`, ``m``.`username`, ``m``.`boards`, ``m``.`type`,
$query = query("SELECT ``m``.`id`, ``m``.`username`, ``m``.`boards`, ``m``.`type`, ``m``.`email`,
``ml``.`time` last, ``ml``.`text` action
FROM ``mods`` AS m
LEFT JOIN (
@ -2125,7 +2160,7 @@ function mod_users() {
FROM ``modlogs``
GROUP BY `mod`
) AS ml2 USING (`mod`, time)
) AS ml ON m.id = ml.`mod` ORDER BY ``m``.`type` DESC;") or error(db_error());
) AS ml ON m.id = ml.`mod` GROUP BY ``m``.`id` ORDER BY ``m``.`type` DESC;") or error(db_error());
$users = $query->fetchAll(PDO::FETCH_ASSOC);
foreach ($users as &$user) {

View File

@ -134,6 +134,7 @@ CREATE TABLE IF NOT EXISTS `mods` (
`salt` char(32) CHARACTER SET ascii NOT NULL,
`type` smallint(2) NOT NULL,
`boards` text CHARACTER SET utf8 NOT NULL,
`email` varchar(1024) DEFAULT '',
PRIMARY KEY (`id`),
UNIQUE KEY `id` (`id`,`username`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4 AUTO_INCREMENT=1 ;

View File

@ -17,6 +17,7 @@ if (active_page == 'catalog') $(function(){
var value = this.value, old;
$(".grid-li").removeClass("grid-size-vsmall");
$(".grid-li").removeClass("grid-size-small");
$(".grid-li").removeClass("grid-size-medium");
$(".grid-li").removeClass("grid-size-large");
$(".grid-li").addClass("grid-size-"+value);
catalog.image_size = value;
@ -35,4 +36,14 @@ if (active_page == 'catalog') $(function(){
if (catalog.image_size !== undefined) {
$('#image_size').val(catalog.image_size).trigger('change');
}
$('div.thread').on('click', function(e) {
if ($(this).css('overflow-y') === 'hidden') {
$(this).css('overflow-y', 'auto');
$(this).css('width', '100%');
} else {
$(this).css('overflow-y', 'hidden');
$(this).css('width', 'auto');
}
});
});

View File

@ -664,7 +664,7 @@ elseif (isset($_POST['post'])) {
}
}
if ($config['allowed_tags'] && $post['op'] && isset($_POST['tag']) && isset($config['allowed_tags'][$_POST['tag']])) {
if ($config['allowed_tags'] && $post['op'] && isset($_POST['tag']) && $_POST['tag'] && isset($config['allowed_tags'][$_POST['tag']])) {
$post['body'] .= "\n<tinyboard tag>" . $_POST['tag'] . "</tinyboard>";
}

View File

@ -24,13 +24,10 @@ main {
}
/* Tables */
table {
margin: auto;
width: 100%;
}
table {
margin: auto;
}
table.board-list-table {
width: 100%;
}
table tbody td {
@ -317,7 +314,7 @@ div.post img.icon {
padding: 0;
}
div.post i.fa {
div.post i.fa, div.thread i.fa {
margin: 0 4px;
font-size: 16px;
}
@ -781,6 +778,16 @@ pre {
max-height: 192px;
}
.theme-catalog div.grid-size-medium img {
max-height: 33%;
max-width: 95%
}
.theme-catalog div.grid-size-medium {
min-width:200px; max-width: 200px;
max-height: 274px;
}
.theme-catalog div.grid-size-large img {
max-height: 40%;
max-width: 95%
@ -1237,9 +1244,6 @@ div.boardlist a {
div.mix {
display: inline-block;
}
.theme-catalog div.thread:hover {
overflow-y: auto; width: 100%
}
/* Mona Font */
.aa {

View File

@ -69,14 +69,15 @@ form table tr th {
color:#C5C8C6
}
div.ban h2 {
background:#FCA;
background:#282A2E;
color:inherit
}
div.ban {
border-color:#800
border-color:#282A2E;
}
div.ban p {
color:#000
div.ban {
color:#C5C8C6;
background-color: inherit;
}
div.pages {
background:#1d1f21;
@ -191,4 +192,4 @@ table.board-list-table .board-tags .board-cell:hover {
}
table.board-list-table tr:nth-of-type( even ) .board-tags .board-cell {
background: #282a2e;
}
}

View File

@ -7,6 +7,7 @@
<tr><th>Subtitle</th><td><input name="subtitle" type="text"> <span class="unimportant">{% trans %}(must be < 200 chars){% endtrans %}</td></tr>
<tr><th>{% trans %}Username{% endtrans %}</th><td><input name="username" type="text"> <span class="unimportant">{% trans %}(must contain only alphanumeric, periods and underscores){% endtrans %}</span></td></tr>
<tr><th>{% trans %}Password{% endtrans %}</th><td><input name="password" type="text" value="{{ password }}" readonly> <span class="unimportant">{% trans %}(write this down){% endtrans %}</span></td></tr>
<tr><th>{% trans %}Email{% endtrans %}</th><td><input name="email" type="text" value=""> <span class="unimportant">{% trans %}(optional, for board recovery){% endtrans %}</span></td></tr>
<tr><th>{% trans %}CAPTCHA{% endtrans %}</th><td>{{ captcha['html'] }}<br/>
<input class="captcha_text" name="captcha_text" size="25" maxlength="6" autocomplete="off" type="text">
<input class="captcha_cookie" name="captcha_cookie" type="hidden" autocomplete="off" value="{{ captcha['cookie']|e }}"><br/></td></tr>

32
templates/mod/assets.html Normal file
View File

@ -0,0 +1,32 @@
<div style="text-align:center">
<form action="{{ action }}" method="post" enctype="multipart/form-data">
<input type="hidden" name="token" value="{{ token }}">
<p><small>All board assets must be less than 500KB and either PNG or GIF format. Please be aware that files may be cached by your browser, so make sure to clear your cache if you change one.</small></p>
<h2>Upload new spoiler file</h2>
<p><input type="file" name="spoiler_file"></p>
<p><small>Spoiler file must be 128 x 128.</small></p>
<p>Current spoiler file:<br> <img src="static/assets/{{ board.uri }}/spoiler.png"></p>
<hr/>
<h2>Upload new "file deleted" file</h2>
<p><input type="file" name="deleted_file"></p>
<p><small>"File deleted" file must be 140 x 50.</small></p>
<p>Current "file deleted" file:<br> <img src="static/assets/{{ board.uri }}/deleted.png"></p>
<hr/>
<h2>Upload new "no file" file</h2>
<p><input type="file" name="nofile_file"></p>
<p><small>"No file" file must be 500 x 500.</small></p>
<p>Current "no file" file:<br> <img src="static/assets/{{ board.uri }}/no-file.png" width="255"></p>
<p><input type="submit" value="Upload new file(s)"></p>
</form>
</div>

View File

@ -66,7 +66,7 @@
{% if mod|hasPermission(config.mod.manageusers) %}
<li><a href="?/users">{% trans 'Manage users' %}</a></li>
{% elseif mod|hasPermission(config.mod.change_password) %}
<li><a href="?/users/{{ mod.id }}">{% trans 'Change password' %}</a></li>
<li><a href="?/users/{{ mod.id }}">{% trans 'Edit profile' %}</a> <span class="unimportant hint">(username, email, password)</span></li>
{% endif %}
{% if mod|hasPermission(config.mod.themes) %}
<li><a href="?/themes">{% trans 'Manage themes' %}</a></li>

View File

@ -30,7 +30,8 @@
<option value="fileboard" {% if config.file_board %}selected{% endif %}>File board</option>
</select></td></tr>
<tr><th>{% trans %}Country flags{% endtrans %}</th><td><input type="checkbox" name="country_flags" {% if config.country_flags %}checked{% endif %}></td></tr>
<tr><th>{% trans %}/pol/-style user flags{% endtrans %}<br><span class="unimportant">Enabling this disables country flags<br>Make sure to actually upload some first!</span></th><td><input type="checkbox" name="user_flags" {% if config.user_flag %}checked{% endif %}></td></tr>
<tr><th>{% trans %}/pol/-style user flags{% endtrans %}<br><span class="unimportant">Enabling this disables country flags<br>Make sure to actually upload some first on the flags page!</span></th><td><input type="checkbox" name="user_flags" {% if config.user_flag %}checked{% endif %}></td></tr>
<tr><th>{% trans %}Custom board assets{% endtrans %}<br><span class="unimportant">Enabling this uses your custom spoiler/deleted/no file images.<br>Make sure to actually upload some first on the assets page or they will 404!</span></th><td><input type="checkbox" name="custom_assets" {% if config.custom_assets %}checked{% endif %}></td></tr>
<tr><th>{% trans %}Forced anonymous{% endtrans %}</th><td><input type="checkbox" name="field_disable_name" {% if config.field_disable_name %}checked{% endif %}></td></tr>
<tr><th>{% trans %}YouTube/Voocaroo embedding{% endtrans %}</th><td><input type="checkbox" name="enable_embedding" {% if config.enable_embedding %}checked{% endif %}></td></tr>
<tr class='imgboard'><th>{% trans %}Require image for OP{% endtrans %}</th><td><input type="checkbox" name="force_image_op" {% if config.force_image_op %}checked{% endif %}></td></tr>
@ -75,7 +76,7 @@
</td></tr>
<tr class='fileboard'><th>{% trans %}Disable OP image upload{% endtrans %}</th><td><input type="checkbox" name="allowed_ext_op" {% if config.allowed_ext_op %}checked{% endif %}>
<label> (<input type="checkbox" name="allowed_ext_op_video" {% if config.allowed_ext_op and 'webm' in config.allowed_ext_op %}checked{% endif %}> also allow video upload)</label></td></tr>
<tr class='fileboard imgboard'><th>{% trans %}Keep original filename{% endtrans %}</th><td><input type="checkbox" name="anal_filenames" {% if config.filename_func == 'filename_func' %}checked{% endif %}></td></tr>
<tr class='fileboard'><th>{% trans %}Keep original filename{% endtrans %}</th><td><input type="checkbox" name="anal_filenames" {% if config.filename_func == 'filename_func' %}checked{% endif %}></td></tr>
</tr>
<tr><th>{% trans %}Max images per post{% endtrans %}</th><td><select name="max_images">{% for i in 1..5 %}<option value="{{ i }}" {% if config.max_images == i %} selected {% endif %}>{{ i }}</option>{% endfor %}</select></td></tr>
</table>
@ -88,6 +89,7 @@
<p style="text-align:center"><a href="?/banners/{{board.uri}}">{% trans %}Edit board banners{% endtrans %}</a></p>
<p style="text-align:center"><a href="?/assets/{{board.uri}}">{% trans %}Edit board assets{% endtrans %}</a></p>
<p style="text-align:center"><a href="?/flags/{{board.uri}}">{% trans %}Edit board flags{% endtrans %}</a></p>
<p style="text-align:center"><a href="?/volunteers/{{board.uri}}">{% trans %}Edit board volunteers{% endtrans %}</a></p>
<p style="text-align:center"><a href="?/tags/{{board.uri}}">{% trans %}Edit board tags{% endtrans %}</a></p>

View File

@ -8,9 +8,9 @@
<input type="hidden" name="token" value="{{ token }}">
<table>
<tr>
<th>{% trans 'Username' %}</th>
<th>{% trans 'Username' %}<br/>{% if not mod|hasPermission(config.mod.editusers) %}<small style="font-weight:normal">({% trans 'warning: changing your username<br/>will log you out and change all occurrences<br/>of your old username to the new one in<br/>your board\'s logs' %}){% endif %}</th>
<td>
{% if new or mod|hasPermission(config.mod.editusers) %}
{% if new or mod|hasPermission(config.mod.edit_profile) %}
<input size="20" maxlength="30" type="text" name="username" value="{{ user.username|e }}" autocomplete="off">
{% else %}
{{ user.username|e }}
@ -20,13 +20,23 @@
<tr>
<th>{% trans 'Password' %}{% if not new %} <small style="font-weight:normal">({% trans 'new; optional' %})</small>{% endif %}</th>
<td>
{% if new or (mod|hasPermission(config.mod.editusers) or (mod|hasPermission(config.mod.change_password) and user.id == mod.id)) %}
{% if new or (mod|hasPermission(config.mod.editusers) or (mod|hasPermission(config.mod.edit_profile) and user.id == mod.id)) %}
<input size="20" maxlength="30" type="password" name="password" value="" autocomplete="off">
{% else %}
-
{% endif %}
</td>
</tr>
<tr>
<th>{% trans 'Email' %}<br/> <small style="font-weight:normal">({% trans 'if you forget your board password<br/>email admin@8chan.co from this<br/>address to request a reset; optional' %})</small></th>
<td>
{% if new or (mod|hasPermission(config.mod.editusers) or (mod|hasPermission(config.mod.edit_profile) and user.id == mod.id)) %}
<input size="20" maxlength="1024" type="text" name="email" value="{{ user.email|e }}" autocomplete="off">
{% else %}
-
{% endif %}
</td>
</tr>
{% if new %}
<tr>
<th>{% trans 'Group' %}</th>
@ -42,6 +52,7 @@
</td>
</tr>
{% endif %}
{% if mod|hasPermission(config.mod.editusers) %}
<tr>
<th>{% trans 'Boards' %}</th>
<td>
@ -73,6 +84,7 @@
</ul>
</td>
</tr>
{% endif %}
</table>
<ul style="padding:0;text-align:center;list-style:none">

View File

@ -3,6 +3,7 @@
<th>{% trans 'ID' %}</th>
<th>{% trans 'Username' %}</th>
<th>{% trans 'Type' %}</th>
<th>{% trans 'Email' %}</th>
<th>{% trans 'Boards' %}</th>
{% if mod|hasPermission(config.mod.modlog) %}
<th>{% trans 'Last action' %}</th>
@ -27,6 +28,9 @@
<em>{% trans 'Unknown' %}</em> ({{ user.type }})
{% endif %}
</td>
<td>
{{ user.email|e }}
</td>
<td>
{% if user.boards == '' %}
<em>{% trans 'none' %}</em>

View File

@ -5,7 +5,7 @@
{% for file in post.files %}
<div class="file{% if post.num_files > 1 %} multifile" style="width:{{ file.thumbwidth + 40 }}px"{% else %}"{% endif %}>
{% if file.file == 'deleted' %}
<img class="post-image deleted" src="{{ config.image_deleted }}" alt="" />
<img class="post-image deleted" src="{{ config.root }}{{ config.image_deleted }}" alt="" />
{% else %}
<p class="fileinfo">File: <a href="{{ config.uri_img }}{{ file.file }}">{{ file.file }}</a> <span class="unimportant">
(

View File

@ -0,0 +1,28 @@
{% if post.sticky %}
{% if config.font_awesome %}
<i class="fa fa-thumb-tack" title="Sticky"></i>
{% else %}
<img class="icon" title="Sticky" src="{{ config.image_sticky }}" alt="Sticky" />
{% endif %}
{% endif %}
{% if post.locked %}
{% if config.font_awesome %}
<i class="fa fa-lock" title="Locked"></i>
{% else %}
<img class="icon" title="Locked" src="{{ config.image_locked }}" alt="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 %}
<i class="fa fa-anchor" title="Bumplocked"></i>
{% else %}
<img class="icon" title="Bumplocked" src="{{ config.image_bumplocked }}" alt="Bumplocked" />
{% endif %}
{% endif %}
{% if post.cycle %}
{% if config.font_awesome %}
<i class="fa fa-refresh" title="Cyclical ({{ config.cycle_limit }})"></i>
{% else %}
<img class="icon" title="Cyclical ({{ config.cycle_limit }})" src="{{ config.image_sticky }}" alt="Cyclical" />
{% endif %}
{% endif %}

View File

@ -229,12 +229,9 @@
{% if not config.field_disable_password or (mod and post.mod|hasPermission(config.mod.bypass_field_disable, board.uri)) %}<tr>
<th>
{% trans %}Password{% endtrans %}
<!-- For Chrom(e|ium) -->
<input type='text' style='display: none'>
<input type='password' style='display: none'>
</th>
<td>
<input type="password" name="password" value="" size="12" maxlength="18" autocomplete="off">
<input type="text" name="password" value="" size="12" maxlength="18" autocomplete="off">
<span class="unimportant hint">{% trans %}(For file and post deletion.){% endtrans %}</span>
</td>
</tr>{% endif %}

View File

@ -17,34 +17,7 @@
{% include 'post/poster_id.html' %}&nbsp;
<a class="post_no" id="post_no_{{ post.id }}" onclick="highlightReply({{ post.id }})" href="{% if isnoko50 %}{{ post.link('', config.file_page50) }}{% else %}{{ post.link }}{% endif %}">No.</a>
<a class="post_no" onclick="citeReply({{ post.id }})" href="{% if isnoko50 %}{{ post.link('q', config.file_page50) }}{% else %}{{ post.link('q') }}{% endif %}">{{ post.id }}</a>
{% if post.sticky %}
{% if config.font_awesome %}
<i class="fa fa-thumb-tack" title="Sticky"></i>
{% else %}
<img class="icon" title="Sticky" src="{{ config.image_sticky }}" alt="Sticky" />
{% endif %}
{% endif %}
{% if post.locked %}
{% if config.font_awesome %}
<i class="fa fa-lock" title="Locked"></i>
{% else %}
<img class="icon" title="Locked" src="{{ config.image_locked }}" alt="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 %}
<i class="fa fa-anchor" title="Bumplocked"></i>
{% else %}
<img class="icon" title="Bumplocked" src="{{ config.image_bumplocked }}" alt="Bumplocked" />
{% endif %}
{% endif %}
{% if post.cycle %}
{% if config.font_awesome %}
<i class="fa fa-refresh" title="Cyclical ({{ config.cycle_limit }})"></i>
{% else %}
<img class="icon" title="Cyclical ({{ config.cycle_limit }})" src="{{ config.image_sticky }}" alt="Cyclical" />
{% endif %}
{% endif %}
{% include 'post/mod_attributes.html' %}
{% if index %}
<a href="{{ post.root }}{{ board.dir }}{{ config.dir.res }}{{ config.file_page|sprintf(post.id) }}">[{% trans %}Reply{% endtrans %}]</a>
{% endif %}

View File

@ -8,7 +8,7 @@
<td><a class="post_no" onclick="citeReply({{ post.id }})" href="{{ post.link('q') }}">{{ post.id }}</a>
<td>{% include 'post/name.html' %}
{% include 'post/flag.html' %}
<td>[<a href="{{ config.uri_img }}{{ post.files[0].file }}">{{ post.files[0].filename|e|bidi_cleanup }}</a>]
<td>[<a target="_blank" href="{{ config.uri_img }}{{ post.files[0].file }}">{{ post.files[0].filename|e|bidi_cleanup }}</a>]
<td>{% if post.modifiers['tag'] %}[{{ post.modifiers['tag']|e }}]{% endif %}
<td>{% include 'post/subject.html' %}
{% if post.sticky %}

View File

@ -32,6 +32,7 @@
<select id="image_size" style="display: inline-block">
<option value="vsmall">{% trans 'Very small' %}</option>
<option selected value="small">{% trans 'Small' %}</option>
<option value="medium">{% trans 'Medium' %}</option>
<option value="large">{% trans 'Large' %}</option>
</select>
<div class="threads">
@ -44,6 +45,7 @@
data-id="{{ post.id }}"
data-sticky="{% if post.sticky %}true{% else %}false{% endif %}"
data-locked="{% if post.locked %}true{% else %}false{% endif %}"
data-cycle="{% if post.cycle %}true{% else %}false{% endif %}"
>
<div class="thread grid-li grid-size-small">
<a href="{{post.link}}">
@ -55,7 +57,7 @@
id="img-{{ post.id }}" data-subject="{% if post.subject %}{{ post.subject|e }}{% endif %}" data-name="{{ post.name|e }}" data-muhdifference="{{ post.muhdifference }}" class="{{post.board}} thread-image" title="{{post.bump|date('%b %d %H:%M')}}">
</a>
<div class="replies">
<strong>R: {{ post.reply_count }} / I: {{ post.image_count }}{% if post.sticky %} (sticky){% endif %}</strong>
<strong>R: {{ post.reply_count }} / I: {{ post.image_count }} / P: {{ (loop.index // config.threads_per_page) + 1 }} {% include 'post/mod_attributes.html' %} </strong>
{% if post.subject %}
<p class="intro">
<span class="subject">

View File

@ -76,13 +76,17 @@
if ($files[0]) {
if ($files[0]->file == 'deleted') {
$post['file'] = $config['image_deleted'];
$post['file'] = $config['root'] . $config['image_deleted'];
}
else if($files[0]->thumb == 'spoiler') {
$post['file'] = '/' . $config['spoiler_image'];
$post['file'] = $config['root'] . $config['spoiler_image'];
}
else {
$post['file'] = $config['uri_thumb'] . $files[0]->thumb;
if ($files[0]->thumb == 'file') {
$post['file'] = $config['root'] . sprintf($config['file_thumb'], 'file.png');
} else {
$post['file'] = $config['uri_thumb'] . $files[0]->thumb;
}
$post['fullimage'] = $config['uri_img'] . $files[0]->file;
}
}