aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cgi/api.py4
-rw-r--r--cgi/formatting.py8
-rw-r--r--cgi/framework.py4
-rw-r--r--cgi/img.py64
-rw-r--r--cgi/manage.py104
-rw-r--r--cgi/oekaki.py6
-rw-r--r--cgi/post.py6
-rw-r--r--cgi/templates/base_top.html7
-rw-r--r--cgi/templates/board.0.html4
-rw-r--r--cgi/templates/board.html6
-rw-r--r--cgi/templates/home.html9
-rw-r--r--cgi/templates/manage/mod.html6
-rw-r--r--cgi/templates/mobile/txt_newthread.html10
-rw-r--r--cgi/templates/navbar.html4
-rw-r--r--cgi/templates/revision.html2
-rw-r--r--cgi/templates/txt_base_top.html7
-rwxr-xr-xcgi/weabot.py46
17 files changed, 157 insertions, 140 deletions
diff --git a/cgi/api.py b/cgi/api.py
index 0c6d61a..09e7d75 100644
--- a/cgi/api.py
+++ b/cgi/api.py
@@ -12,9 +12,9 @@ def api(self, path_split):
try:
self.output = api_process(self, path_split)
except APIError as e:
- self.output = api_error("error", e.message)
+ self.output = api_error("error", str(e))
except UserError as e:
- self.output = api_error("failed", e.message)
+ self.output = api_error("failed", str(e))
except Exception as e:
import sys
import traceback
diff --git a/cgi/formatting.py b/cgi/formatting.py
index 3da64da..97f44a6 100644
--- a/cgi/formatting.py
+++ b/cgi/formatting.py
@@ -119,7 +119,7 @@ def iphash(ip, post, t, useid, mobile, agent, cap_id, hide_end, has_countrycode)
word = ',' + str(day) # IDs change every 24 hours
word += ',' + str(t) # IDs vary depending on thread
- id = getb64(getMD5(ip + word + Settings.SECRET))[:8]
+ id = getb64(getMD5(ip + word + Settings.SECRET))[-10:-2]
if hide_end:
id += '*'
@@ -160,6 +160,8 @@ def iphash(ip, post, t, useid, mobile, agent, cap_id, hide_end, has_countrycode)
elif (not has_countrycode and not addressIsTor(ip) and
(addressIsProxy(ip) or not addressIsES(ip))):
id += '!'
+
+ logging.info("{} {} {}".format(ip, agent, id))
return id
@@ -202,7 +204,7 @@ def videoThumbs(message):
'span': match.span(0),
'url': match.group(1),
}
- if len(v_ids) >= Settings.VIDEO_THUMBS_LIMIT:
+ if len(v_ids) > Settings.VIDEO_THUMBS_LIMIT:
raise UserError("Has incluído muchos videos en tu mensaje. El máximo es %d." % Settings.VIDEO_THUMBS_LIMIT)
if videos:
@@ -245,7 +247,7 @@ def fixMobileLinks(message):
board = Settings._.BOARD
# If textboard
- if board["board_type"] == '1':
+ if board["board_type"] == 1:
message = re.compile(r'<a href="/(\w+)/read/(\d+)(\.html)?/*(.+)"').sub(
r'<a href="/cgi/mobileread/\1/\2/\4"', message)
else:
diff --git a/cgi/framework.py b/cgi/framework.py
index 86683dd..38ba2ad 100644
--- a/cgi/framework.py
+++ b/cgi/framework.py
@@ -306,6 +306,10 @@ def getb64(data):
return base64.b64encode(bytes(data, 'utf-8')).decode('utf-8')
+def decodeb64(data):
+ return base64.b64decode(bytes(data, 'utf-8'))
+
+
def getRandomLine(filename):
import random
f = open(filename, 'r')
diff --git a/cgi/img.py b/cgi/img.py
index 7759b23..67114fb 100644
--- a/cgi/img.py
+++ b/cgi/img.py
@@ -31,6 +31,7 @@ def processImage(post, data, t, originalname, spoiler=False):
# get image information
content_type, width, height, size, extra = getImageInfo(data)
+ #raise Exception(repr(getImageInfo(data)))
logging.info("{} {} {}".format(content_type, width, height))
# check the size is fine
@@ -52,7 +53,7 @@ def processImage(post, data, t, originalname, spoiler=False):
raise UserError(_("This image has already been posted %s.") % ('<a href="' + Settings.BOARDS_URL + board['dir'] + '/res/' + str(is_duplicate[1]) + '.html#' + str(is_duplicate[2]) + '">' + _("here") + '</a>'))
# prepare file names
- if used_filetype['preserve_name'] == '1':
+ if used_filetype['preserve_name']:
file_base = os.path.splitext(originalname)[0] # use original filename
else:
file_base = '%d' % int(t * 1000) # generate timestamp name
@@ -90,11 +91,10 @@ def processImage(post, data, t, originalname, spoiler=False):
if not used_filetype['image']:
# make thumbnail
logging.debug("Generating thumbnail")
- file_thumb_width, file_thumb_height = getThumbDimensions(
- width, height, maxsize)
+ file_thumb_width, file_thumb_height = getThumbDimensions(width, height, maxsize)
try:
- if used_filetype['ffmpeg_thumb'] == '1':
+ if used_filetype['ffmpeg_thumb']:
# use ffmpeg to make thumbnail
if used_filetype['mime'][:5] == 'video':
# Create preview for video AND spoiler it if necessary
@@ -144,7 +144,7 @@ def processImage(post, data, t, originalname, spoiler=False):
call_wrap(args)
except subprocess.CalledProcessError as e:
os.remove(file_path)
- logging.error("Thumbnail creation failure: " + e.output)
+ logging.error("Thumbnail creation failure: " + str(e.output))
raise UserError(_("Thumbnail creation failure.") + ' ('+str(e.returncode)+')')
# check if thumbnail was truly created
@@ -166,14 +166,14 @@ def processImage(post, data, t, originalname, spoiler=False):
post["thumb_height"] = file_thumb_height
else:
# Don't thumbnail and use mime image
- if board["board_type"] == '0':
+ if board["board_type"] == 0:
post["thumb"] = used_filetype['image']
- post["thumb_width"] = '120'
- post["thumb_height"] = '120'
+ post["thumb_width"] = 120
+ post["thumb_height"] = 120
else:
post["thumb"] = used_filetype['image'].split(".")[0] + '_small.png'
- post["thumb_width"] = '90'
- post["thumb_height"] = '90'
+ post["thumb_width"] = 90
+ post["thumb_height"] = 90
# calculate size (bytes)
post["file_size"] = len(data)
@@ -202,22 +202,22 @@ def extraInfo(mime, file_name, file_path):
else:
stream = info['streams'][0]
- extra['codec'] = stream.get('codec_name', '').encode('utf-8')
+ extra['codec'] = stream.get('codec_name', '')
format = info['format']
if 'bit_rate' in format:
extra['codec'] += ' ~%d kbps' % int(int(format['bit_rate']) / 1000)
if 'tags' in format:
extra['title'] = format['tags'].get(
- 'TITLE', format['tags'].get('title', '')).encode('utf-8')
+ 'TITLE', format['tags'].get('title', ''))
extra['artist'] = format['tags'].get(
- 'ARTIST', format['tags'].get('artist', '')).encode('utf-8')
+ 'ARTIST', format['tags'].get('artist', ''))
if extra['title'] or extra['artist']:
credit_str = ' - '.join((extra['artist'],
extra['title'])) + ' '
if 'tags' in stream:
- extra['title'] = stream['tags'].get('TITLE', '').encode('utf-8')
- extra['artist'] = stream['tags'].get('ARTIST', '').encode('utf-8')
+ extra['title'] = stream['tags'].get('TITLE', '')
+ extra['artist'] = stream['tags'].get('ARTIST', '')
if extra['title'] or extra['artist']:
credit_str = ' - '.join((extra['artist'],
extra['title'])) + ' '
@@ -234,13 +234,13 @@ def extraInfo(mime, file_name, file_path):
def getImageInfo(data):
size = len(data)
- height = -1
- width = -1
+ height = 0
+ width = 0
extra = {}
content_type = ""
# handle GIFs
- if (size >= 10) and data[:6] in ("GIF87a", "GIF89a"):
+ if (size >= 10) and data[:6] in (b"GIF87a", b"GIF89a"):
# Check to see if content_type is correct
content_type = "image/gif"
w, h = struct.unpack("<HH", data[6:10])
@@ -251,7 +251,7 @@ def getImageInfo(data):
# Bytes 0-7 are below, 4-byte chunk length, then 'IHDR'
# and finally the 4-byte width, height
elif ((size >= 24) and data.startswith(b"\211PNG\r\n\032\n")
- and (data[12:16] == "IHDR")):
+ and (data[12:16] == b"IHDR")):
content_type = "image/png"
w, h = struct.unpack(">LL", data[16:24])
width = int(w)
@@ -313,22 +313,22 @@ def getImageInfo(data):
info = ffprobe(data)
# handle mp4
- elif (size >= 8) and data[4:12] in ["ftypmp42", "ftypisom"]:
+ elif (size >= 8) and data[4:12] in [b"ftypmp42", b"ftypisom"]:
content_type = "video/mp4"
# handle ogg formats (vorbis/opus)
- elif (size >= 64) and data[:4] == "OggS":
- if data[28:35] == "\x01vorbis":
+ elif (size >= 64) and data[:4] == b"OggS":
+ if data[28:35] == b"\x01vorbis":
content_type = "audio/ogg"
- elif data[28:36] == "OpusHead":
+ elif data[28:36] == b"OpusHead":
content_type = "audio/opus"
# handle MP3
- elif (size >= 64) and (data[:3] == "ID3" or data[:3] == "\xFF\xFB"):
+ elif (size >= 64) and (data[:3] == b"ID3" or data[:3] == b"\xFF\xFB"):
content_type = "audio/mpeg"
# handle MOD
- elif (size >= 64) and data[1080:1084] == "M.K.":
+ elif (size >= 64) and data[1080:1084] == b"M.K.":
content_type = "audio/mod"
# handle XM
@@ -336,23 +336,23 @@ def getImageInfo(data):
content_type = "audio/xm"
# handle S3M
- elif (size >= 64) and data[25:32] == "\x00\x00\x00\x1A\x10\x00\x00":
+ elif (size >= 64) and data[25:32] == b"\x00\x00\x00\x1A\x10\x00\x00":
content_type = "audio/s3m"
# handle PDF
- elif (size >= 4) and data[:7] == "%PDF-1.":
+ elif (size >= 4) and data[:7] == b"%PDF-1.":
content_type = "application/pdf"
# handle Shockwave Flash
- elif (size >= 3) and data[:3] in ["CWS", "FWS"]:
+ elif (size >= 3) and data[:3] in [b"CWS", b"FWS"]:
content_type = "application/x-shockwave-flash"
# handle torrent
- elif (size >= 11) and data[:11] == "d8:announce":
+ elif (size >= 11) and data[:11] == b"d8:announce":
content_type = "application/x-bittorrent"
# handle PDF
- elif (size >= 2) and data[:2] == "PK":
+ elif (size >= 2) and data[:2] == b"PK":
content_type = "application/epub+zip"
if content_type.startswith("video"):
@@ -386,6 +386,7 @@ def ffprobe_f(filename):
def call_wrap(args):
+ logging.info("Calling: " + repr(args))
subprocess.check_output(args, stderr=subprocess.STDOUT)
@@ -394,6 +395,9 @@ def getThumbDimensions(width, height, maxsize):
Calculate dimensions to use for a thumbnail with maximum width/height of
<maxsize>, keeping aspect ratio
"""
+ if not width or not height:
+ return 0, 0
+
wratio = (float(maxsize) / float(width))
hratio = (float(maxsize) / float(height))
diff --git a/cgi/manage.py b/cgi/manage.py
index 0053f54..02eaf41 100644
--- a/cgi/manage.py
+++ b/cgi/manage.py
@@ -225,30 +225,27 @@ def manage(self, path_split):
pass
else:
action = 'add'
- try:
- if self.formdata.get('user') and self.formdata.get('pass'):
- username_taken = FetchOne(
- 'SELECT * FROM `staff` WHERE `username` = %s LIMIT 1', (self.formdata['user'],))
- if not username_taken:
- if self.formdata['rights'] in [0, 1, 2, 3]:
- action_taken = True
- pass_hash = genPasswdHash(
- self.formdata['pass'])
-
- InsertDb("INSERT INTO `staff` (`username`, `password`, `added`, `rights`) VALUES (%s, %s, %s, %s)",
- (self.formdata['user'], pass_hash, timestamp(), self.formdata['rights']))
- message = _('Staff member added.')
- logAction(
- staff_account['username'], 'Added staff account for ' + self.formdata['user'])
-
- template_filename = "message.html"
- else:
+ if self.formdata.get('user') and self.formdata.get('pass'):
+ username_taken = FetchOne(
+ 'SELECT COUNT(1) as count FROM `staff` WHERE `username` = %s LIMIT 1', (self.formdata['user'],))
+ if not username_taken['count']:
+ if self.formdata['rights'] in ['0', '1', '2', '3']:
action_taken = True
- message = _(
- 'That username is already in use.')
+ pass_hash = genPasswdHash(
+ self.formdata['pass'])
+
+ InsertDb("INSERT INTO `staff` (`username`, `password`, `added`, `rights`) VALUES (%s, %s, %s, %s)",
+ (self.formdata['user'], pass_hash, timestamp(), self.formdata['rights']))
+ message = _('Staff member added.')
+ logAction(
+ staff_account['username'], 'Added staff account for ' + self.formdata['user'])
+
template_filename = "message.html"
- except:
- pass
+ else:
+ action_taken = True
+ message = _(
+ 'That username is already in use.')
+ template_filename = "message.html"
if not action_taken:
action_taken = True
@@ -342,14 +339,14 @@ def manage(self, path_split):
board['id'], postid))
if not permanently:
- deletePost(path_split[4], None, '2', imageonly)
+ deletePost(path_split[4], None, 2, imageonly)
else:
- deletePost(path_split[4], None, '0', imageonly)
+ deletePost(path_split[4], None, 0, imageonly)
regenerateHome()
# Borrar denuncias
- UpdateDb("DELETE FROM `reports` WHERE `postid` = '" +
- _mysql.escape_string(path_split[4])+"'")
+ UpdateDb("DELETE FROM `reports` WHERE `postid` = %s",
+ (int(path_split[4]),))
boards = FetchAll(
'SELECT `name`, `dir` FROM `boards` ORDER BY `dir`')
@@ -376,26 +373,27 @@ def manage(self, path_split):
# Nos vamos al board y ubicamos el post
board = setBoard(path_split[3])
- post = FetchOne('SELECT `parentid`, `locked` FROM `posts` WHERE `boardid` = ' +
- board['id'] + ' AND `id` = \'' + _mysql.escape_string(path_split[4]) + '\' LIMIT 1')
+ postid = int(path_split[4])
+ post = FetchOne('SELECT `parentid`, `locked` FROM `posts` WHERE `boardid` = %s AND `id` = %s LIMIT 1',
+ (board['id'], postid))
if not post:
message = _('Unable to locate a post with that ID.')
template_filename = "message.html"
else:
- if post['parentid'] != '0':
+ if not post['parentid']:
message = _('Post is not a thread opener.')
template_filename = "message.html"
else:
- if post['locked'] == '0':
+ if not post['locked']:
# Cerrar si esta abierto
setLocked = 1
else:
# Abrir si esta cerrado
setLocked = 0
- UpdateDb("UPDATE `posts` SET `locked` = %d WHERE `boardid` = '%s' AND `id` = '%s' LIMIT 1" % (
- setLocked, board["id"], _mysql.escape_string(path_split[4])))
- threadUpdated(path_split[4])
+ UpdateDb("UPDATE `posts` SET `locked` = %s WHERE `boardid` = %s AND `id` = %s LIMIT 1",
+ (setLocked, board["id"], postid))
+ threadUpdated(postid)
if setLocked == 1:
message = _('Thread successfully closed.')
logAction(staff_account['username'], _('Closed thread %s') % (
@@ -419,11 +417,11 @@ def manage(self, path_split):
message = 'Solo se puede aplicar permasage en un hilo abierto.'
template_filename = "message.html"
else:
- if post['parentid'] != '0':
+ if post['parentid']:
message = 'Post is not a thread opener.'
template_filename = "message.html"
else:
- if post['locked'] == '2':
+ if post['locked'] == 2:
# Sacar permasage
setPermasaged = 0
else:
@@ -835,8 +833,8 @@ def manage(self, path_split):
if form_submitted:
if verifyPasswd(staff_account['username'], self.formdata['oldpassword']):
if self.formdata['newpassword'] == self.formdata['newpassword2']:
- UpdateDb('UPDATE `staff` SET `password` = \'' + genPasswdHash(
- self.formdata['newpassword']) + '\' WHERE `id` = ' + staff_account['id'] + ' LIMIT 1')
+ UpdateDb('UPDATE `staff` SET `password` = %s WHERE `id` = %s LIMIT 1',
+ (genPasswdHash(self.formdata['newpassword']), staff_account['id']))
message = _(
'Password successfully changed. Please log out and log back in.')
template_filename = "message.html"
@@ -1019,20 +1017,20 @@ def manage(self, path_split):
if path_split[4] == 'delete':
board = setBoard(path_split[5])
- post = FetchOne('SELECT id, parentid, message, INET6_NTOA(ip) AS ip FROM `posts` WHERE `boardid` = ' +
- board['id'] + ' AND `id` = \'' + _mysql.escape_string(path_split[6]) + '\' LIMIT 1')
+ post = FetchOne('SELECT id, parentid, message, INET6_NTOA(ip) AS ip FROM `posts` WHERE `boardid` = %s AND `id` = %s LIMIT 1',
+ (board['id'], path_split[6]))
if not post:
message = _(
'Unable to locate a post with that ID.')
else:
- deletePost(path_split[6], None)
+ deletePost(post['id'], None)
- if post['parentid'] != '0':
+ if post['parentid']:
threadUpdated(post['parentid'])
else:
regenerateFrontPages()
- message = "Post %s eliminado permanentemente" % ('/' + board['dir'] + '/' + post['id'])
+ message = "Post %s eliminado permanentemente" % ('/' + board['dir'] + '/' + str(post['id']))
logAction(staff_account['username'], message + ' desde papelera. Contenido: ' + post['message'] + ' IP: ' + post['ip'])
# Delete more than 1 post
@@ -1107,9 +1105,8 @@ def manage(self, path_split):
else:
cboard = 'all'
posts = FetchAll("SELECT posts.id, posts.timestamp, timestamp_formatted, IS_DELETED, INET6_NTOA(posts.ip) AS ip, posts.message, dir FROM `posts` INNER JOIN `boards` ON boardid = boards.id WHERE IS_DELETED %s ORDER BY `timestamp` DESC LIMIT %d, %d" % (
- _mysql.escape_string(type_condition), currentpage*pagesize, pagesize))
- totals = FetchOne("SELECT COUNT(id) FROM `posts` WHERE IS_DELETED %s" %
- _mysql.escape_string(type_condition), 0)
+ type_condition, currentpage*pagesize, pagesize))
+ totals = FetchOne("SELECT COUNT(id) AS count FROM `posts` WHERE IS_DELETED %s" % type_condition)
template_filename = "recyclebin.html"
template_values = {'message': message,
@@ -1119,7 +1116,7 @@ def manage(self, path_split):
if not skip:
# Calculate number of pages
- total = int(totals[0])
+ total = totals["count"]
pages = int(math.ceil(total / pagesize))
# Create delete form
@@ -1198,7 +1195,8 @@ def manage(self, path_split):
if board_dir != '':
action_taken = True
board_exists = FetchOne(
- 'SELECT * FROM `boards` WHERE `dir` = \'' + _mysql.escape_string(board_dir) + '\' LIMIT 1')
+ "SELECT * FROM `boards` WHERE `dir` = %s LIMIT 1",
+ (board_dir,))
if not board_exists:
os.mkdir(Settings.ROOT_DIR + board_dir)
os.mkdir(Settings.ROOT_DIR + board_dir + '/res')
@@ -1209,8 +1207,8 @@ def manage(self, path_split):
os.mkdir(Settings.IMAGES_DIR + board_dir + '/mobile')
os.mkdir(Settings.IMAGES_DIR + board_dir + '/cat')
if os.path.exists(Settings.ROOT_DIR + board_dir) and os.path.isdir(Settings.ROOT_DIR + board_dir):
- UpdateDb('INSERT INTO `boards` (`dir`, `name`) VALUES (\'' + _mysql.escape_string(
- board_dir) + '\', \'' + _mysql.escape_string(self.formdata['name']) + '\')')
+ UpdateDb("INSERT INTO `boards` (`dir`, `name`) VALUES (%s, %s)",
+ (board_dir, self.formdata['name']))
board = setBoard(board_dir)
f = open(Settings.ROOT_DIR +
board['dir'] + '/.htaccess', 'w')
@@ -1848,7 +1846,7 @@ def manage(self, path_split):
(currentpage*pagesize, pagesize))
for report in reports:
- keyname = 'i' + report['id']
+ keyname = 'i' + str(report['id'])
if keyname in self.formdata:
# Ignore here
UpdateDb("DELETE FROM `reports` WHERE `id` = %s",
@@ -1968,7 +1966,8 @@ def manage(self, path_split):
# delete all starting posts first
op_posts = FetchAll(
- "SELECT `id`, `message` FROM posts WHERE parentid = 0 AND boardid = '" + board['id'] + "' AND ip = INET6_ATON('" + str(ip) + "')")
+ "SELECT `id`, `message` FROM posts WHERE parentid = 0 AND boardid = %s AND ip = INET6_ATON(%s)",
+ (board['id'], ip))
for post in op_posts:
deletePost(post['id'], None)
@@ -1976,7 +1975,8 @@ def manage(self, path_split):
deletedPostsTotal += 1
replies = FetchAll(
- "SELECT `id`, `message`, `parentid` FROM posts WHERE parentid != 0 AND boardid = '" + board['id'] + "' AND ip = INET6_ATON('" + str(ip) + "')")
+ "SELECT `id`, `message`, `parentid` FROM posts WHERE parentid != 0 AND boardid = %s AND ip = INET6_ATON(%s)",
+ (board['id'], ip))
for post in replies:
deletePost(post['id'], None, '2')
diff --git a/cgi/oekaki.py b/cgi/oekaki.py
index b5fddf3..d12e94e 100644
--- a/cgi/oekaki.py
+++ b/cgi/oekaki.py
@@ -40,7 +40,7 @@ def oekaki(self, path_split):
# Obtenemos el board
board = setBoard(self.formdata['board'])
- if board['allow_oekaki'] != '1':
+ if not board['allow_oekaki']:
raise UserError('Esta sección no soporta oekaki.')
# Veamos a quien le estamos respondiendo
@@ -140,7 +140,7 @@ def oekaki(self, path_split):
except:
parentid = None
- if board['allow_oekaki'] != '1':
+ if not board['allow_oekaki']:
raise UserError('Esta sección no soporta oekaki.')
ts = int(time.time())
@@ -200,7 +200,7 @@ def write_from_base64(fname, data):
if data.startswith("data:image/png;base64,"):
data = data[22:]
data = data.replace(' ', '+')
- data = data.decode('base64')
+ data = decodeb64(data)
with open(fname, 'wb') as f:
f.write(data)
return "OK"
diff --git a/cgi/post.py b/cgi/post.py
index 22d8197..89c2a19 100644
--- a/cgi/post.py
+++ b/cgi/post.py
@@ -474,7 +474,7 @@ def catalog(sort=''):
thread['message'] = thread['message'].replace('<br />', ' ')
thread['message'] = thread['message'].split("<hr />")[0]
thread['message'] = re.compile(r"<[^>]*?>", re.DOTALL | re.IGNORECASE).sub('', thread['message'])
- thread['message'] = thread['message'].decode('utf-8')[:cutFactor].encode('utf-8')
+ thread['message'] = thread['message'][:cutFactor]
thread['message'] = re.compile(r"&(.(?!;))*$", re.DOTALL | re.IGNORECASE).sub('', thread['message']) # Removes incomplete HTML entities
return renderTemplate("catalog.html", {"threads": threads, "i_sort": sort})
@@ -543,7 +543,7 @@ def dynamicRead(parentid, ranges, mobile=False):
import json
with open(fname) as f:
thread = json.load(f)
- thread['posts'] = [dict(list(zip(thread['keys'], row))) for row in thread['posts']]
+ thread['posts'] = [dict(zip(thread['keys'], row)) for row in thread['posts']]
template_fname = "txt_archive.html"
else:
raise UserError('El hilo no existe.')
@@ -687,7 +687,7 @@ def regenerateBoard(everything=False):
for post in op_posts:
regenerateThreadPage(post["id"])
-def deletePost(postid, password, deltype='0', imageonly=False, quick=False):
+def deletePost(postid, password, deltype=0, imageonly=False, quick=False):
"""
Remove post from database and unlink file (if present), along with all replies
if supplied post is a thread
diff --git a/cgi/templates/base_top.html b/cgi/templates/base_top.html
index 4c86614..a1f0431 100644
--- a/cgi/templates/base_top.html
+++ b/cgi/templates/base_top.html
@@ -1,6 +1,5 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
- "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
+<!DOCTYPE html>
+<html lang="es">
<head>
<?py if 'matome' in _context: ?>
<title>#{matome} - #{board_long}</title>
@@ -9,7 +8,7 @@
<?py else: ?>
<title>#{title}</title>
<?py #endif ?>
- <meta http-equiv="Content-Type" content="application/xhtml+xml;charset=utf-8" />
+ <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<?py if replythread and 'threads' in _context and 'preview' in _context: ?>
<meta property="og:site_name" content="Bienvenido a Internet IB" />
diff --git a/cgi/templates/board.0.html b/cgi/templates/board.0.html
index 1557cbc..0f5f31f 100644
--- a/cgi/templates/board.0.html
+++ b/cgi/templates/board.0.html
@@ -196,7 +196,7 @@
#{post['message']}
</blockquote>
<?py if not replythread and post['shortened']: ?>
- <blockquote class="abbrev">(Post muy largo... Presiona <a href="#{boards_url}#{board}/res/#{post['id'] if post['parentid'] == "0" else post['parentid']}.html##{post['id']}">aqu&iacute;</a> para verlo completo.)</blockquote>
+ <blockquote class="abbrev">(Post muy largo... Presiona <a href="#{boards_url}#{board}/res/#{post['id'] if not post['parentid'] else post['parentid']}.html##{post['id']}">aqu&iacute;</a> para verlo completo.)</blockquote>
<?py #endif ?>
<?py #endif ?>
<?py if post['parentid'] == "0": ?>
@@ -227,4 +227,4 @@
<?py if pagenav: ?>
<div class="pg">#{pagenav}</div>
<?py #endif ?>
-<?py include('templates/base_bottom.html') ?> \ No newline at end of file
+<?py include('templates/base_bottom.html') ?>
diff --git a/cgi/templates/board.html b/cgi/templates/board.html
index 7173fde..70718b8 100644
--- a/cgi/templates/board.html
+++ b/cgi/templates/board.html
@@ -163,9 +163,9 @@
</a>
<?py #endif ?>
<a name="#{post['id']}"></a>
- <?py if post['IS_DELETED'] == '1': ?>
+ <?py if post['IS_DELETED'] == 1: ?>
<span class="deleted">No.#{post['id']} eliminado por usuario.</span>
- <?py elif post['IS_DELETED'] == '2': ?>
+ <?py elif post['IS_DELETED'] == 2: ?>
<span class="deleted">No.#{post['id']} eliminado por miembro del staff.</span>
<?py else: ?>
<div class="info"><label><input type="checkbox" name="delete" value="#{post['id']}" />
@@ -235,7 +235,7 @@
#{post['message']}
</blockquote>
<?py if not replythread and post['shortened']: ?>
- <blockquote class="abbrev">(Post muy largo... Presiona <a href="#{boards_url}#{board}/res/#{post['id'] if post['parentid'] == "0" else post['parentid']}.html##{post['id']}">aqu&iacute;</a> para verlo completo.)</blockquote>
+ <blockquote class="abbrev">(Post muy largo... Presiona <a href="#{boards_url}#{board}/res/#{post['id'] if not post['parentid'] else post['parentid']}.html##{post['id']}">aqu&iacute;</a> para verlo completo.)</blockquote>
<?py #endif ?>
<?py if int(post['expires_alert']): ?>
<div style="color:red;font-weight:bold;">Este hilo es viejo y desaparecerá pronto.</div>
diff --git a/cgi/templates/home.html b/cgi/templates/home.html
index 04fbf72..a9ca238 100644
--- a/cgi/templates/home.html
+++ b/cgi/templates/home.html
@@ -1,8 +1,7 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
- "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
+<!DOCTYPE html>
+<html lang="es">
<head>
- <meta http-equiv="content-type" content="application/xhtml+xml; charset=UTF-8" />
+ <meta charset="utf-8">
<meta name="description" content="Bienvenido a Internet es un sitio para la discusión de distintos temas, sin necesidad de registrarse." />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Bienvenido a Internet BBS/IB</title>
@@ -101,7 +100,7 @@
</div>
</td>
</tr>
-<tr><td colspan="2" id="footer">Bienvenido a Internet ★ 2010-2021</td></tr>
+<tr><td colspan="2" id="footer">Bienvenido a Internet ★ 2010-2022</td></tr>
</table>
<div id="preview" style="display:none;"></div>
</body>
diff --git a/cgi/templates/manage/mod.html b/cgi/templates/manage/mod.html
index c76965e..bb93c9d 100644
--- a/cgi/templates/manage/mod.html
+++ b/cgi/templates/manage/mod.html
@@ -77,14 +77,14 @@
</td>
<td><a href="#{cgi_url}manage/ipshow?ip=#{p['ip']}">#{p['ip']}</a></td>
<td style="white-space:nowrap;">
- <?py if p['IS_DELETED'] == '0': ?>
+ <?py if not p['IS_DELETED']: ?>
<a href="#{cgi_url}manage/delete/#{dir}/#{p['id']}">Eliminar</a>
<a href="#{cgi_url}manage/delete/#{dir}/#{p['id']}?ban=true">&</a>
<a href="/cgi/manage/ban?ip=#{p['ip']}">Ban</a>
- <?py elif p['IS_DELETED'] == '1': ?>
+ <?py elif p['IS_DELETED'] == 1: ?>
<a href="#{cgi_url}manage/recyclebin/0/restore/#{dir}/#{p['id']}">Recuperar</a>
<abbr title="Eliminado por usuario">[1]</abbr>
- <?py elif p['IS_DELETED'] == '2': ?>
+ <?py elif p['IS_DELETED'] == 2: ?>
<a href="#{cgi_url}manage/recyclebin/0/restore/#{dir}/#{p['id']}">Recuperar</a>
<abbr title="Eliminado por staff">[2]</abbr>
<?py #endif ?>
diff --git a/cgi/templates/mobile/txt_newthread.html b/cgi/templates/mobile/txt_newthread.html
index aafcdfa..2414303 100644
--- a/cgi/templates/mobile/txt_newthread.html
+++ b/cgi/templates/mobile/txt_newthread.html
@@ -1,10 +1,10 @@
<?py include('templates/mobile/base_top.html') ?>
-<body class="#{"txt" if board_type == '1' else "img"}" data-brd="#{board}">
+<body class="#{"txt" if board_type == 1 else "img"}" data-brd="#{board}">
<div class="top">
<a href="//m.bienvenidoainternet.org"><img src="#{static_url}css/img/0back.png" /><br />Home</a>
#{board_name}
</div>
-<?py if board_type == '1': ?>
+<?py if board_type == 1: ?>
<div class="bar"><a href="#{cgi_url}mobile/#{board}">Portada</a><a href="#{cgi_url}mobilelist/#{board}">Todos los hilos</a><a href="#{cgi_url}mobilenew/#{board}" class="sel">Nuevo hilo</a></div>
<?py else: ?>
<div class="bar"><a href="#{cgi_url}mobile/#{board}">Portada</a><a href="#{cgi_url}mobilelist/#{board}">Lista</a><a href="#{cgi_url}mobilecat/#{board}">Cat&aacute;logo</a><a href="#{cgi_url}mobilenew/#{board}" class="sel">Nuevo hilo</a></div>
@@ -13,13 +13,13 @@
<input type="hidden" name="board" value="#{board}" /> <input type="hidden" name="mobile" value="true" /><input type="hidden" name="password" value="" />
<div style="display:none;"><input type="text" name="name" maxlength="50" /><input type="text" name="email" maxlength="50" /></div>
<?py if not disable_subject: ?>
- <input class="fld imp" type="text" name="subject" placeholder="Asunto#{" (opcional)" if board_type == '0' else ""}" maxlength="100" />
+ <input class="fld imp" type="text" name="subject" placeholder="Asunto#{" (opcional)" if board_type == 0 else ""}" maxlength="100" />
<?py #endif ?>
<?py if not disable_name: ?>
<input class="fld" type="text" name="fielda" placeholder="Nombre (opcional)" maxlength="50" />
<?py #endif ?>
<input class="fld" type="text" name="fieldb" placeholder="E-mail (opcional)" maxlength="50" />
- <textarea name="message" rows="#{"8" if board_type == '1' else "6"}"></textarea>
+ <textarea name="message" rows="#{"8" if board_type == 1 else "6"}"></textarea>
<?py if allow_images: ?>
<div class="file"><input type="file" name="file" class="fld" />
<?py if allow_spoilers: ?>
@@ -32,4 +32,4 @@
<div class="rules">Formatos permitidos: #{', '.join(supported_filetypes).upper()}<br />Tamaño máximo: #{maxsize} KB</div>
<?py #endif ?>
</body>
-</html> \ No newline at end of file
+</html>
diff --git a/cgi/templates/navbar.html b/cgi/templates/navbar.html
index 29e5276..ef0096e 100644
--- a/cgi/templates/navbar.html
+++ b/cgi/templates/navbar.html
@@ -3,7 +3,9 @@
<a href="/juegos/">Juegos</a>
<a href="/musica/">M&uacute;sica</a>
<a href="/letras/">Humanidades</a>
+<a href="/drogas/">Psicotrópicos</a>
<a href="/zonavip/">Club VIP</a>
+<a href="/consejos/">Consejos</a>
<a href="/world/">World</a>
|
<a href="/dqn/">Club DQN</a>
@@ -12,4 +14,4 @@
<a href="/o/">Oekaki</a>
<a href="/0/">Cero</a>
|
-<a href="/bai/">Meta</a> \ No newline at end of file
+<a href="/bai/">Meta</a>
diff --git a/cgi/templates/revision.html b/cgi/templates/revision.html
index 9028ec6..1a46c7f 100644
--- a/cgi/templates/revision.html
+++ b/cgi/templates/revision.html
@@ -1 +1 @@
-0.10.5
+0.10.8
diff --git a/cgi/templates/txt_base_top.html b/cgi/templates/txt_base_top.html
index 84dc320..41ce920 100644
--- a/cgi/templates/txt_base_top.html
+++ b/cgi/templates/txt_base_top.html
@@ -1,6 +1,5 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
- "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
+<!DOCTYPE html>
+<html lang="es">
<head>
<?py if replythread and threads: ?>
<title>#{threads[0]['subject']} - #{board_name}@Bienvenido a Internet BBS</title>
@@ -9,7 +8,7 @@
<?py else: ?>
<title>#{title}</title>
<?py #endif ?>
- <meta http-equiv="Content-Type" content="application/xhtml+xml;charset=utf-8" />
+ <meta charset="utf-8">
<?py if replythread and threads: ?>
<meta property="og:site_name" content="Bienvenido a Internet BBS" />
<meta property="twitter:site" content="Bienvenido a Internet BBS" />
diff --git a/cgi/weabot.py b/cgi/weabot.py
index 636eb02..5d565d5 100755
--- a/cgi/weabot.py
+++ b/cgi/weabot.py
@@ -23,7 +23,7 @@ from formatting import *
from post import *
from img import *
-__version__ = "0.10.5"
+__version__ = "0.10.8"
# Set to True to disable weabot's exception routing and enable profiling
_DEBUG = False
@@ -202,7 +202,7 @@ class weabot(object):
OpenDb()
board = setBoard(path_split[2])
caught = True
- if board['board_type'] != '1':
+ if board['board_type'] != 1:
raise UserError("No disponible para esta sección.")
self.output = threadList(0)
elif path_split[1] == "mobile":
@@ -311,21 +311,18 @@ class weabot(object):
caught = True
OpenDb()
board = FetchOne("SELECT `id`, `dir`, `board_type` FROM `boards` WHERE `secret` = 0 AND `id` <> 1 AND `id` <> 13 AND `id` <> 34 ORDER BY RAND() LIMIT 1")
- thread = FetchOne("SELECT `id`, `timestamp` FROM `posts` WHERE `parentid` = 0 AND `boardid` = %s ORDER BY RAND() LIMIT 1" % board['id'])
- if board['board_type'] == '1':
- url = Settings.HOME_URL + \
- board['dir'] + '/read/' + thread['timestamp'] + '/'
+ thread = FetchOne("SELECT `id`, `timestamp` FROM `posts` WHERE `parentid` = 0 AND `boardid` = %s ORDER BY RAND() LIMIT 1", (board['id'],))
+ if board['board_type'] == 1:
+ url = f"{Settings.HOME_URL}{board['dir']}/read/{thread['timestamp']}/"
else:
- url = Settings.HOME_URL + \
- board['dir'] + '/res/' + thread['id'] + '.html'
+ url = f"{Settings.HOME_URL}{board['dir']}/res/{thread['id']}.html"
self.output += '<html xmlns="http://www.w3.org/1999/xhtml"><meta http-equiv="refresh" content="0;url=%s" /><body><p>...</p></body></html>' % url
elif path_split[1] == "nostalgia":
caught = True
OpenDb()
thread = FetchOne(
"SELECT `timestamp` FROM `archive` WHERE `boardid` = 9 AND `timestamp` < 1462937230 ORDER BY RAND() LIMIT 1")
- url = Settings.HOME_URL + '/zonavip/read/' + \
- thread['timestamp'] + '/'
+ url = f"{Settings.HOME_URL}/zonavip/read/{thread['timestamp']}/"
self.output += '<html xmlns="http://www.w3.org/1999/xhtml"><meta http-equiv="refresh" content="0;url=%s" /><body><p>...</p></body></html>' % url
elif path_split[1] == "banned":
OpenDb()
@@ -404,9 +401,20 @@ class weabot(object):
_STARTTIME = time.process_time() # Comment if not debug
if Settings.PROXY_BANS and ip not in Settings.PROXY_WHITELIST and (boarddir not in Settings.EXCLUDE_GLOBAL_BANS):
- if addressIsTor(ip) or addressIsProxy(ip) or addressIsBannedCountry(ip) or not addressIsES(ip):
+ if addressIsTor(ip):
+ logging.warn("Proxy: Tor %s" % ip)
+ raise UserError("Proxy prohibido.")
+ if addressIsProxy(ip):
+ logging.warn("Proxy: Proxy %s" % ip)
+ raise UserError("Proxy prohibido.")
+ if addressIsBannedCountry(ip):
+ logging.warn("Proxy: Banned country %s" % ip)
+ raise UserError("Proxy prohibido.")
+ if not addressIsES(ip):
+ logging.warn("Proxy: Not ES %s" % ip)
raise UserError("Proxy prohibido.")
if hostIsBanned(ip):
+ logging.warn("Proxy: Blacklisted host %s" % ip)
raise UserError("Sufijo de host en lista negra.")
# open database
@@ -595,7 +603,7 @@ class weabot(object):
self.environ["HTTP_USER_AGENT"], cap_id, hide_end, (board["countrycode"] in [1, 2]))
# use for future file checks
- xfile = (file is not None or oek_file)
+ xfile = (file or oek_file)
# textboard inforcements (change it to settings maybe?)
if board['board_type'] == 1:
@@ -640,7 +648,7 @@ class weabot(object):
if file and not noimage:
post = processImage(post, file, t, file_original,
- (spoil and board['allow_spoilers'] == '1'))
+ (spoil and board['allow_spoilers']))
if oek_file:
# Remove temporary oekaki file if everything went right
@@ -652,11 +660,11 @@ class weabot(object):
pass # Just keep it if anything went wrong
# slip
- if board["slip"] != '0':
+ if board["slip"]:
slips = []
# name
- if board["slip"] in ['1', '3']:
+ if board["slip"] in [1, 3]:
if time.strftime("%H") in ['00', '24'] and time.strftime("%M") == '00' and time.strftime("%S") == '00':
host_nick = '000000'
else:
@@ -762,15 +770,15 @@ class weabot(object):
post["name"] += " <em>[%s]</em>" % country
# set expiration date if necessary
- if board["maxage"] != 0 and not post["parentid"]:
+ if board["maxage"] > 0 and not post["parentid"]:
if board["dir"] == '2d':
date_format = '%m月%d日'
date_format_y = '%Y年%m月'
else:
date_format = '%d/%m'
date_format_y = '%m/%Y'
- post["expires"] = int(t) + (int(board["maxage"]) * 86400)
- if int(board["maxage"]) >= 365:
+ post["expires"] = int(t) + (board["maxage"] * 86400)
+ if board["maxage"] >= 365:
date_format = date_format_y
post["expires_formatted"] = datetime.datetime.fromtimestamp(
post["expires"]).strftime(date_format)
@@ -959,7 +967,7 @@ class weabot(object):
raise UserError(_("Post doesn't exist."))
# generate link
- if board["board_type"] == '1':
+ if board["board_type"] == 1:
parent_post = get_parent_post(post["parentid"], board["id"])
link = "/%s/read/%s/%s" % (board["dir"],
parent_post["timestamp"], postshow)