diff options
Diffstat (limited to 'cgi/weabot.py')
-rwxr-xr-x | cgi/weabot.py | 235 |
1 files changed, 119 insertions, 116 deletions
diff --git a/cgi/weabot.py b/cgi/weabot.py index 38efa7c..720916d 100755 --- a/cgi/weabot.py +++ b/cgi/weabot.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 # coding=utf-8 # Remove the first line to use the env command to locate python @@ -9,8 +9,8 @@ import datetime import random import cgi import logging -import _mysql -from Cookie import SimpleCookie +from MySQLdb import _mysql +from http.cookies import SimpleCookie import tenjin import manage @@ -23,7 +23,7 @@ from formatting import * from post import * from img import * -__version__ = "0.8.10" +__version__ = "0.10.0" # Set to True to disable weabot's exception routing and enable profiling _DEBUG = False @@ -35,7 +35,7 @@ class weabot(object): def __init__(self, environ, start_response): global _DEBUG - logging.basicConfig(filename='weabot.log', format='%(asctime)s %(levelname)s %(message)s', level=logging.INFO) + logging.basicConfig(filename='weabot.log', format='%(asctime)s %(levelname)s %(message)s', level=logging.DEBUG) self.environ = environ if self.environ["PATH_INFO"].startswith("/weabot.py/"): @@ -61,9 +61,9 @@ class weabot(object): else: try: self.run() - except UserError, message: + except UserError as message: self.error(message) - except Exception, inst: + except Exception as inst: logging.exception(inst) import sys @@ -74,11 +74,12 @@ class weabot(object): self.exception(type(inst), inst, detail) # close database and finish - CloseDb() + #CloseDb() def __iter__(self): self.handleResponse() self.start("200 OK", self.headers) + self.output = self.output.encode('utf-8') yield self.output def error(self, message): @@ -115,7 +116,7 @@ class weabot(object): def handleResponse(self): if self._newcookies: - for newcookie in self._newcookies.values(): + for newcookie in list(self._newcookies.values()): self.headers.append( ("Set-Cookie", newcookie.output(header=""))) @@ -129,8 +130,8 @@ class weabot(object): caught = False if Settings.FULL_MAINTENANCE: - raise UserError, _( - "%s is currently under maintenance. We'll be back.") % Settings.SITE_TITLE + raise UserError(_( + "%s is currently under maintenance. We'll be back.") % Settings.SITE_TITLE) if len(path_split) > 1: if path_split[1] == "post": @@ -138,7 +139,7 @@ class weabot(object): caught = True if 'password' not in self.formdata: - raise UserError, "El request está incompleto." + raise UserError("El request está incompleto.") # let's get all the POST data we need ip = self.environ["REMOTE_ADDR"] @@ -156,7 +157,7 @@ class weabot(object): oek_file = self.formdata.get('oek_file') password = self.formdata.get('password', '') noimage = self.formdata.get('noimage') - mobile = ("mobile" in self.formdata.keys()) + mobile = ("mobile" in self.formdata) # call post function (post_url, ttaken, unused) = self.make_post(ip, boarddir, parent, trap1, trap2, name, @@ -202,7 +203,7 @@ class weabot(object): board = setBoard(path_split[2]) caught = True if board['board_type'] != '1': - raise UserError, "No disponible para esta sección." + raise UserError("No disponible para esta sección.") self.output = threadList(0) elif path_split[1] == "mobile": OpenDb() @@ -261,18 +262,15 @@ class weabot(object): caught = True # Redirect to ban page if user is banned - if addressIsBanned(self.environ['REMOTE_ADDR'], board["dir"], blind_only=True): - raise UserError, '<meta http-equiv="refresh" content="0; url=/cgi/banned/%s">' % board["dir"] + if Settings.ENABLE_BANS and addressIsBanned(self.environ['REMOTE_ADDR'], board["dir"], blind_only=True): + raise UserError('<meta http-equiv="refresh" content="0; url=/cgi/banned/%s">' % board["dir"]) if len(path_split) > 4 and path_split[4] and board['board_type'] == '1': - # try: self.output = dynamicRead(int(path_split[3]), path_split[4], True) - # except: - # self.output = threadPage(path_split[3], True) - elif board['board_type'] == '1': - self.output = threadPage(0, True, path_split[3]) + elif board['board_type'] == 1: + self.output = threadPage(0, True, int(path_split[3])) else: - self.output = threadPage(path_split[3], True) + self.output = threadPage(int(path_split[3]), True) elif path_split[1] == "catalog": OpenDb() board = setBoard(path_split[2]) @@ -334,15 +332,15 @@ class weabot(object): bans = FetchAll("SELECT * FROM `bans` WHERE INET6_ATON('"+self.environ["REMOTE_ADDR"]+"') BETWEEN `ipstart` AND `ipend`") if bans: for ban in bans: - if ban["boards"] != "": + if ban["boards"]: boards = pickle.loads(ban["boards"]) - if ban["boards"] == "" or path_split[2] in boards: + if ban["boards"] or path_split[2] in boards: caught = True if ban["boards"]: boards_str = '/' + '/, /'.join(boards) + '/' else: boards_str = 'todas' - if ban["until"] != "0": + if ban["until"]: expire = formatTimestamp(ban["until"]) else: expire = "" @@ -374,8 +372,8 @@ class weabot(object): board = setBoard(path_split[2]) # Redirect to ban page if user is banned - if addressIsBanned(self.environ['REMOTE_ADDR'], board["dir"], blind_only=True): - raise UserError, '<meta http-equiv="refresh" content="0; url=/cgi/banned/%s">' % board["dir"] + if Settings.ENABLE_BANS and addressIsBanned(self.environ['REMOTE_ADDR'], board["dir"], blind_only=True): + raise UserError('<meta http-equiv="refresh" content="0; url=/cgi/banned/%s">' % board["dir"]) self.output = dynamicRead(int(path_split[3]), path_split[4]) elif path_split[1] == "preview": @@ -386,7 +384,7 @@ class weabot(object): message = format_post( self.formdata["message"], self.environ["REMOTE_ADDR"], self.formdata["parentid"]) self.output = message - except Exception, messagez: + except Exception as messagez: self.output = "Error: " + \ str(messagez) + " : " + str(self.formdata) elif path_split[1] == "mod": @@ -400,11 +398,16 @@ class weabot(object): # Redirect the user back to the front page self.output += '<html xmlns="http://www.w3.org/1999/xhtml"><body><meta http-equiv="refresh" content="0;url=%s" /><p>--> --> --></p></body></html>' % Settings.HOME_URL + CloseDb() + def make_post(self, ip, boarddir, parent, trap1, trap2, name, email, subject, message, file, file_original, spoil, oek_file, password, noimage, mobile): - _STARTTIME = time.clock() # Comment if not debug + _STARTTIME = time.process_time() # Comment if not debug - if hostIsBanned(ip): - raise UserError, "Sufijo de host en lista negra." + 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): + raise UserError("Proxy prohibido.") + if hostIsBanned(ip): + raise UserError("Sufijo de host en lista negra.") # open database OpenDb() @@ -412,25 +415,21 @@ class weabot(object): # set the board board = setBoard(boarddir) - if Settings.PROXY_BAN and (board["dir"] not in Settings.EXCLUDE_GLOBAL_BANS): - if addressIsTor(ip) or addressIsProxy(ip) or addressIsBannedCountry(ip) or not addressIsES(ip): - raise UserError, "Proxy prohibido." - # check length of fields if len(name) > 50: - raise UserError, "El campo de nombre es muy largo." + raise UserError("El campo de nombre es muy largo.") if len(email) > 50: - raise UserError, "El campo de e-mail es muy largo." + raise UserError("El campo de e-mail es muy largo.") if len(subject) > 100: - raise UserError, "El campo de asunto es muy largo." + raise UserError("El campo de asunto es muy largo.") if len(message) > 8000: - raise UserError, "El campo de mensaje es muy largo." + raise UserError("El campo de mensaje es muy largo.") if message.count('\n') > 50: - raise UserError, "El mensaje tiene muchos saltos de línea." + raise UserError("El mensaje tiene muchos saltos de línea.") # anti-spam trap if trap1 or trap2: - raise UserError, "Te quedan tres días de vida." + raise UserError("Te quedan tres días de vida.") # Create a single datetime now so everything syncs up t = time.time() @@ -441,14 +440,14 @@ class weabot(object): regenerateAccess() # Redirect to ban page if user is banned - if addressIsBanned(ip, board["dir"]): - raise UserError, '<meta http-equiv="refresh" content="0; url=/cgi/banned/%s">' % board["dir"] + if Settings.ENABLE_BANS and addressIsBanned(ip, board["dir"]): + raise UserError('<meta http-equiv="refresh" content="0; url=/cgi/banned/%s">' % board["dir"]) # Disallow posting if the site OR board is in maintenance if Settings.MAINTENANCE and board["dir"] != 'polka': - raise UserError, _("%s is currently under maintenance. We'll be back.") % Settings.SITE_TITLE + raise UserError(_("%s is currently under maintenance. We'll be back.") % Settings.SITE_TITLE) if board["locked"] == '1': - raise UserError, _("This board is closed. You can't post in it.") + raise UserError(_("This board is closed. You can't post in it.")) # create post object post = Post(board["id"]) @@ -465,7 +464,7 @@ class weabot(object): post["parentid"] = parent_post['id'] post["bumped"] = parent_post['bumped'] if parent_post['locked'] == '1': - raise UserError, _("The thread is closed. You can't post in it.") + raise UserError(_("The thread is closed. You can't post in it.")) # check if the user is flooding flood_check(t, post, board["id"]) @@ -550,10 +549,10 @@ class weabot(object): # compatibility : old id function if 'id' in parent_post["email"]: - board["useid"] = '3' + board["useid"] = 3 if 'id' in post["email"]: - board["useid"] = '3' + board["useid"] = 3 if extend: try: @@ -591,35 +590,35 @@ class weabot(object): tim = post["timestamp"] # make ID hash - if board["useid"] != '0': + if board["useid"]: post["timestamp_formatted"] += ' ID:' + iphash(ip, post, tim, board["useid"], mobile, self.environ["HTTP_USER_AGENT"], cap_id, hide_end, (board["countrycode"] in ['1', '2'])) # use for future file checks - xfile = (file or oek_file) + xfile = (file is not None or oek_file) # textboard inforcements (change it to settings maybe?) - if board['board_type'] == '1': + if board['board_type'] == 1: if not post["parentid"] and not post["subject"]: - raise UserError, _( - "You must enter a title to create a thread.") + raise UserError(_( + "You must enter a title to create a thread.")) if not post["message"]: - raise UserError, _("Please enter a message.") + raise UserError(_("Please enter a message.")) else: if not post["parentid"] and not xfile and not noimage: - raise UserError, _( - "You must upload an image first to create a thread.") + raise UserError(_( + "You must upload an image first to create a thread.")) if not xfile and not post["message"]: - raise UserError, _( - "Please enter a message or upload an image to reply.") + raise UserError(_( + "Please enter a message or upload an image to reply.")) # check if this post is allowed if post["parentid"]: - if file and board['allow_image_replies'] == '0': - raise UserError, _("Image replies not allowed.") + if file and not board['allow_image_replies']: + raise UserError(_("Image replies not allowed.")) else: - if file and board['allow_images'] == '0': - raise UserError, _("No images allowed.") + if file and not board['allow_images']: + raise UserError(_("No images allowed.")) # use default values when missing / remove sage from wrong fields if (not post["name"] and not post["tripcode"]) or (post["name"].lower() == 'sage'): @@ -637,7 +636,7 @@ class weabot(object): with open(fname, 'rb') as f: file = f.read() except: - raise UserError, "Imposible leer la imagen oekaki." + raise UserError("Imposible leer la imagen oekaki.") if file and not noimage: post = processImage(post, file, t, file_original, @@ -700,7 +699,7 @@ class weabot(object): host = getHost(ip) if host: - for k, v in isps.iteritems(): + for k, v in isps.items(): if k in host: host_nick = v break @@ -708,7 +707,7 @@ class weabot(object): slips.append(host_nick) # hash - if board["slip"] in ['1', '3']: + if board["slip"] in [1, 3]: if hide_end: slips.append( '-'.join((getMD5(ip + post["name"])[:4], '****'))) @@ -720,7 +719,7 @@ class weabot(object): '-'.join((getMD5(ip)[:4], getMD5(self.environ["HTTP_USER_AGENT"])[:4]))) # host - if board["slip"] == '2': + if board["slip"] == 2: if hide_end: host = '★' else: @@ -743,7 +742,7 @@ class weabot(object): slips.append(host) # IP - if board["slip"] == '3': + if board["slip"] == 3: if hide_end: host = '[*.*.*.*]' else: @@ -755,7 +754,7 @@ class weabot(object): post["tripcode"] += " (%s)" % ' '.join(slips) # country code - if board["countrycode"] == '1': + if board["countrycode"] == 1: if hide_end or addressIsTor(ip): country = '??' else: @@ -763,7 +762,7 @@ 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月' @@ -784,7 +783,7 @@ class weabot(object): if board["dir"] == 'noticias': # check if there's at least one link if "<a href" not in post["message"]: - raise UserError, "Al momento de crear un hilo en esta sección necesitas incluír al menos 1 link como fuente en tu mensaje." + raise UserError("Al momento de crear un hilo en esta sección necesitas incluír al menos 1 link como fuente en tu mensaje.") # insert icon if needed img_src = '<img src="%s" alt="ico" /><br />' % getRandomIco() @@ -797,11 +796,11 @@ class weabot(object): trimThreads() # fix null references when creating thread - if board["board_type"] == '1' and not post["parentid"]: + if board["board_type"] == 1 and not post["parentid"]: post["message"] = re.compile(r'<a href="/(\w+)/res/0.html/(.+)"').sub( r'<a href="/\1/res/'+str(postid)+r'.html/\2"', post["message"]) - UpdateDb("UPDATE `posts` SET message = '%s' WHERE boardid = '%s' AND id = '%s'" % (_mysql.escape_string( - post["message"]), _mysql.escape_string(board["id"]), _mysql.escape_string(str(postid)))) + UpdateDb("UPDATE `posts` SET message = %s WHERE boardid = %s AND id = %s", + (post["message"], board["id"], postid)) # do operations if replying to a thread (bump, autoclose, update cache) logging.debug("Updating thread") @@ -812,13 +811,15 @@ class weabot(object): # bump if not saged if 'sage' not in post["email"].lower() and parent_post['locked'] != '2': - UpdateDb("UPDATE `posts` SET bumped = %d WHERE (`id` = '%s' OR `parentid` = '%s') AND `boardid` = '%s'" % (post["timestamp"], post["parentid"], post["parentid"], board["id"])) + UpdateDb("UPDATE `posts` SET bumped = %s WHERE (`id` = %s OR `parentid` = %s) AND `boardid` = %s", + (post["timestamp"], post["parentid"], post["parentid"], board["id"])) # check if thread must be closed autoclose_thread(post["parentid"], t, thread_length) # update final attributes (length and last post) - UpdateDb("UPDATE `posts` SET length = %d, last = %d WHERE `id` = '%s' AND `boardid` = '%s'" % (thread_length, post["timestamp"], post["parentid"], board["id"])) + UpdateDb("UPDATE `posts` SET length = %s, last = %s WHERE `id` = %s AND `boardid` = %s", + (thread_length, post["timestamp"], post["parentid"], board["id"])) # update cache threadUpdated(post["parentid"]) @@ -829,13 +830,13 @@ class weabot(object): regenerateHome() # make page redirect - ttaken = timeTaken(_STARTTIME, time.clock()) - noko = 'noko' in email.lower() or (board["board_type"] == '1') + ttaken = timeTaken(_STARTTIME, time.process_time()) + noko = 'noko' in email.lower() or (board["board_type"] == 1) # get new post url post_url = make_url(postid, post, parent_post or post, noko, mobile) - if board['secret'] == '0': + if not board['secret']: # add to recent posts if Settings.ENABLE_RSS: latestAdd(post, thread_length, postid, parent_post) @@ -854,33 +855,33 @@ class weabot(object): board = setBoard(boarddir) if board["dir"] == '0': - raise UserError, "No se pueden eliminar mensajes en esta sección." + raise UserError("No se pueden eliminar mensajes en esta sección.") # check if we have a post id and check it's numeric if not postid: - raise UserError, "Selecciona uno o más mensajes a eliminar." + raise UserError("Selecciona uno o más mensajes a eliminar.") # make sure we have a password if not password: - raise UserError, _("Please enter a password.") + raise UserError(_("Please enter a password.")) to_delete = [] if isinstance(postid, list): - to_delete = [n.value for n in postid] + to_delete = [int(n.value) for n in postid] else: - to_delete = [postid] + to_delete = [int(postid)] # delete posts - if board['board_type'] == '1' and len(to_delete) == 1: + if board['board_type'] == 1 and len(to_delete) == 1: # we should be deleting only one (textboard) # check if it's the last post and delete permanently if so - deltype = '0' + deltype = 0 post = FetchOne("SELECT `id`, `timestamp`, `parentid` FROM `posts` WHERE `boardid` = %s AND `id` = %s LIMIT 1" % ( board["id"], str(to_delete[0]))) - if post['parentid'] != '0': + if post['parentid']: op = get_parent_post(post['parentid'], board['id']) if op['last'] != post['timestamp']: - deltype = '1' + deltype = 1 deletePost(to_delete[0], password, deltype, imageonly) latestRemove(post['id']) @@ -896,10 +897,10 @@ class weabot(object): deletePost(pid, password, board['recyclebin'], imageonly) latestRemove(pid) deleted += 1 - msgs.append('No.%s: Eliminado' % pid) - except UserError, message: + msgs.append('No.%d: Eliminado' % pid) + except UserError as message: errors += 1 - msgs.append('No.%s: %s' % (pid, message)) + msgs.append('No.%d: %s' % (pid, message)) # regenerate home if deleted: @@ -907,8 +908,8 @@ class weabot(object): # show errors, if any if errors: - raise UserError, 'No todos los mensajes pudieron ser eliminados.<br />' + \ - '<br />'.join(msgs) + raise UserError('No todos los mensajes pudieron ser eliminados.<br />' + \ + '<br />'.join(msgs)) # redirect if imageonly: @@ -921,7 +922,7 @@ class weabot(object): def report(self, ip, boarddir, postid, reason, txt, postshow): # don't allow if the report system is off if not Settings.REPORTS_ENABLE: - raise UserError, _('Report system is deactivated.') + raise UserError(_('Report system is deactivated.')) # if there's not a reason, show the report page if reason is None: @@ -931,9 +932,9 @@ class weabot(object): # check reason if not reason: - raise UserError, _("Enter a reason.") + raise UserError(_("Enter a reason.")) if len(reason) > 100: - raise UserError, _("Text too long.") + raise UserError(_("Text too long.")) # open database OpenDb() @@ -942,14 +943,14 @@ class weabot(object): board = setBoard(boarddir) # check if he's banned - if addressIsBanned(ip, board["dir"]): - raise UserError, _("You're banned.") + if Settings.ENABLE_BANS and addressIsBanned(ip, board["dir"]): + raise UserError(_("You're banned.")) # check if post exists post = FetchOne("SELECT `id`, `parentid`, `ip` FROM `posts` WHERE `id` = '%s' AND `boardid` = '%s'" % ( _mysql.escape_string(str(postid)), _mysql.escape_string(board['id']))) if not post: - raise UserError, _("Post doesn't exist.") + raise UserError(_("Post doesn't exist.")) # generate link if board["board_type"] == '1': @@ -989,33 +990,33 @@ class weabot(object): OpenDb() # 1 week = 604800 - query_day = FetchAll("SELECT DATE_FORMAT(FROM_UNIXTIME(FLOOR((timestamp-10800)/86400)*86400+86400), \"%Y-%m-%d\"), COUNT(1), COUNT(IF(parentid=0, 1, NULL)) " + query_day = FetchAll("SELECT DATE_FORMAT(FROM_UNIXTIME(FLOOR((timestamp-10800)/86400)*86400+86400), \"%Y-%m-%d\") AS date, COUNT(1) AS count, COUNT(IF(parentid=0, 1, NULL)) AS threads " "FROM posts " "WHERE (timestamp-10800) > (UNIX_TIMESTAMP()-604800) AND (IS_DELETED = 0) " "GROUP BY FLOOR((timestamp-10800)/86400) " - "ORDER BY FLOOR((timestamp-10800)/86400)", 0) + "ORDER BY FLOOR((timestamp-10800)/86400)") - query_count = FetchOne("SELECT COUNT(1), COUNT(NULLIF(file, '')), VERSION() FROM posts", 0) - total = int(query_count[0]) - total_files = int(query_count[1]) - mysql_ver = query_count[2] + query_count = FetchOne("SELECT COUNT(1) AS posts, COUNT(NULLIF(file, '')) AS files, VERSION() AS version FROM posts") + total = query_count["posts"] + total_files = query_count["files"] + mysql_ver = query_count["version"] - archive_count = FetchOne("SELECT SUM(length) FROM archive", 0) - total_archived = int(archive_count[0]) + archive_count = FetchOne("SELECT SUM(length) AS sum FROM archive") + total_archived = int(archive_count["sum"]) days = [] - for date, count, threads in query_day[1:]: - days.append((date, count, threads)) + for r in query_day[1:]: + days.append((r["date"], r["count"], r["threads"])) - query_b = FetchAll("SELECT id, dir, name FROM boards WHERE boards.secret = 0", 0) + query_b = FetchAll("SELECT id, dir, name FROM boards WHERE boards.secret = 0") boards = [] totalp = 0 - for id, dir, longname in query_b: - bposts = FetchOne("SELECT COUNT(1) FROM posts " - "WHERE '"+str(id)+"' = posts.boardid AND timestamp > ( UNIX_TIMESTAMP(DATE(NOW())) - 2419200 )", 0) - boards.append((dir, longname, int(bposts[0]))) - totalp += int(bposts[0]) + for b in query_b: + bposts = FetchOne("SELECT COUNT(1) AS count FROM posts " + "WHERE posts.boardid = %s AND timestamp > ( UNIX_TIMESTAMP(DATE(NOW())) - 2419200 )", (b['id'],)) + boards.append((b['dir'], b['name'], bposts["count"])) + totalp += bposts["count"] boards = sorted(boards, key=lambda boards: boards[2], reverse=True) @@ -1069,7 +1070,7 @@ class weabot(object): if __name__ == "__main__": - from fcgi import WSGIServer + from flup.server.fcgi import WSGIServer # Psyco is not required, however it will be used if available try: @@ -1084,4 +1085,6 @@ if __name__ == "__main__": except: pass - WSGIServer(weabot).run() + app = WSGIServer(weabot, debug=True, forceCGI=False) + app.run() + |