aboutsummaryrefslogtreecommitdiff
path: root/cgi/weabot.py
diff options
context:
space:
mode:
Diffstat (limited to 'cgi/weabot.py')
-rwxr-xr-xcgi/weabot.py2014
1 files changed, 1038 insertions, 976 deletions
diff --git a/cgi/weabot.py b/cgi/weabot.py
index 398ebfa..1406707 100755
--- a/cgi/weabot.py
+++ b/cgi/weabot.py
@@ -30,995 +30,1057 @@ _DEBUG = False
# Set to True to save performance data to weabot.txt
_LOG = False
+
class weabot(object):
- def __init__(self, environ, start_response):
- global _DEBUG
- self.environ = environ
- if self.environ["PATH_INFO"].startswith("/weabot.py/"):
- self.environ["PATH_INFO"] = self.environ["PATH_INFO"][11:]
-
- self.start = start_response
- self.formdata = getFormData(self)
- self.output = ""
-
- self.handleRequest()
-
- # Localization Code
- lang = gettext.translation('weabot', './locale', languages=[Settings.LANG])
- lang.install()
-
- logTime("**Start**")
- if _DEBUG:
- import cProfile
-
- prof = cProfile.Profile()
- prof.runcall(self.run)
- prof.dump_stats('stats.prof')
- else:
- try:
- self.run()
- except UserError, message:
- self.error(message)
- except Exception, inst:
- import sys, traceback
- exc_type, exc_value, exc_traceback = sys.exc_info()
- detail = ((os.path.basename(o[0]),o[1],o[2],o[3]) for o in traceback.extract_tb(exc_traceback))
- self.exception(type(inst), inst, detail)
-
- # close database and finish
- CloseDb()
- logTime("**End**")
-
- if _LOG:
- logfile = open(Settings.ROOT_DIR + "weabot.txt", "w")
- logfile.write(logTimes())
- logfile.close()
-
- def __iter__(self):
- self.handleResponse()
- self.start("200 OK", self.headers)
- yield self.output
-
- def error(self, message):
- board = Settings._.BOARD
- if board:
- if board['board_type'] == '1':
- info = {}
- info['host'] = self.environ["REMOTE_ADDR"]
- info['name'] = self.formdata.get('fielda', '')
- info['email'] = self.formdata.get('fieldb', '')
- info['message'] = self.formdata.get('message', '')
-
- self.output += renderTemplate("txt_error.html", {"info": info, "error": message})
- else:
- mobile = self.formdata.get('mobile', '')
- if mobile:
- self.output += renderTemplate("mobile/error.html", {"error": message})
+ def __init__(self, environ, start_response):
+ global _DEBUG
+ self.environ = environ
+ if self.environ["PATH_INFO"].startswith("/weabot.py/"):
+ self.environ["PATH_INFO"] = self.environ["PATH_INFO"][11:]
+
+ self.start = start_response
+ self.formdata = getFormData(self)
+ self.output = ""
+
+ self.handleRequest()
+
+ # Localization Code
+ lang = gettext.translation(
+ 'weabot', './locale', languages=[Settings.LANG])
+ lang.install()
+
+ logTime("**Start**")
+ if _DEBUG:
+ import cProfile
+
+ prof = cProfile.Profile()
+ prof.runcall(self.run)
+ prof.dump_stats('stats.prof')
else:
- self.output += renderTemplate("error.html", {"error": message, "boards_url": Settings.BOARDS_URL, "board": board["dir"]})
- else:
- self.output += renderTemplate("exception.html", {"exception": None, "error": message})
-
- def exception(self, type, message, detail):
- self.output += renderTemplate("exception.html", {"exception": type, "error": message, "detail": detail})
-
- def handleRequest(self):
- self.headers = [("Content-Type", "text/html")]
- self.handleCookies()
-
- def handleResponse(self):
- if self._newcookies:
- for newcookie in self._newcookies.values():
- self.headers.append(("Set-Cookie", newcookie.output(header="")))
-
- def handleCookies(self):
- self._cookies = SimpleCookie()
- self._cookies.load(self.environ.get("HTTP_COOKIE", ""))
- self._newcookies = None
-
- def run(self):
- path_split = self.environ["PATH_INFO"].split("/")
- caught = False
-
- if Settings.FULL_MAINTENANCE:
- raise UserError, _("%s is currently under maintenance. We'll be back.") % Settings.SITE_TITLE
-
- if len(path_split) > 1:
- if path_split[1] == "post":
- # Making a post
- caught = True
-
- if 'password' not in self.formdata:
- raise UserError, "El request está incompleto."
-
- # let's get all the POST data we need
- ip = self.environ["REMOTE_ADDR"]
- boarddir = self.formdata.get('board')
- parent = self.formdata.get('parent')
- trap1 = self.formdata.get('name', '')
- trap2 = self.formdata.get('email', '')
- name = self.formdata.get('fielda', '')
- email = self.formdata.get('fieldb', '')
- subject = self.formdata.get('subject', '')
- message = self.formdata.get('message', '')
- file = self.formdata.get('file')
- file_original = self.formdata.get('file_original')
- spoil = self.formdata.get('spoil')
- oek_file = self.formdata.get('oek_file')
- password = self.formdata.get('password', '')
- noimage = self.formdata.get('noimage')
- mobile = ("mobile" in self.formdata.keys())
-
- # call post function
- (post_url, ttaken, unused) = self.make_post(ip, boarddir, parent, trap1, trap2, name, email, subject, message, file, file_original, spoil, oek_file, password, noimage, mobile)
-
- # make redirect
- self.output += make_redirect(post_url, ttaken)
- elif path_split[1] == "environ":
- caught = True
-
- self.output += repr(self.environ)
- elif path_split[1] == "delete":
- # Deleting a post
- caught = True
-
- boarddir = self.formdata.get('board')
- postid = self.formdata.get('delete')
- imageonly = self.formdata.get('imageonly')
- password = self.formdata.get('password')
- mobile = self.formdata.get('mobile')
-
- # call delete function
- self.delete_post(boarddir, postid, imageonly, password, mobile)
- elif path_split[1] == "anarkia":
- import anarkia
- caught = True
- OpenDb()
- anarkia.anarkia(self, path_split)
- elif path_split[1] == "manage":
- caught = True
- OpenDb()
- manage.manage(self, path_split)
- elif path_split[1] == "api":
- import api
- caught = True
- self.headers = [("Content-Type", "application/json"), ("Access-Control-Allow-Origin", "*"), ("Access-Control-Allow-Methods", "PUT, GET, POST, DELETE, OPTIONS"), ("Access-Control-Allow-Headers", "Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With")]
- OpenDb()
- api.api(self, path_split)
- elif path_split[1] == "threadlist":
- OpenDb()
- board = setBoard(path_split[2])
- caught = True
- if board['board_type'] != '1':
- raise UserError, "No disponible para esta sección."
- self.output = threadList(0)
- elif path_split[1] == "mobile":
- OpenDb()
- board = setBoard(path_split[2])
- caught = True
- self.output = threadList(1)
- elif path_split[1] == "mobilelist":
- OpenDb()
- board = setBoard(path_split[2])
- caught = True
- self.output = threadList(2)
- elif path_split[1] == "mobilecat":
- OpenDb()
- board = setBoard(path_split[2])
- caught = True
- self.output = threadList(3)
- elif path_split[1] == "mobilenew":
- OpenDb()
- board = setBoard(path_split[2])
- caught = True
- self.output = renderTemplate('txt_newthread.html', {}, True)
- elif path_split[1] == "mobilehome":
- OpenDb()
- latest_age = getLastAge(Settings.HOME_LASTPOSTS)
- for threads in latest_age:
- content = threads['url']
- content = content.replace('/read/', '/')
- content = content.replace('/res/', '/')
- content = content.replace('.html', '')
- threads['url'] = content
- caught = True
- self.output = renderTemplate('latest.html', {'latest_age': latest_age}, True)
- elif path_split[1] == "mobilenewest":
- OpenDb()
- newthreads = getNewThreads(Settings.HOME_LASTPOSTS)
- for threads in newthreads:
- content = threads['url']
- content = content.replace('/read/', '/')
- content = content.replace('/res/', '/')
- content = content.replace('.html', '')
- threads['url'] = content
- caught = True
- self.output = renderTemplate('newest.html', {'newthreads': newthreads}, True)
- elif path_split[1] == "mobileread":
- OpenDb()
- board = setBoard(path_split[2])
- caught = True
- 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])
+ try:
+ self.run()
+ except UserError, message:
+ self.error(message)
+ except Exception, inst:
+ import sys
+ import traceback
+ exc_type, exc_value, exc_traceback = sys.exc_info()
+ detail = ((os.path.basename(o[0]), o[1], o[2], o[3])
+ for o in traceback.extract_tb(exc_traceback))
+ self.exception(type(inst), inst, detail)
+
+ # close database and finish
+ CloseDb()
+ logTime("**End**")
+
+ if _LOG:
+ logfile = open(Settings.ROOT_DIR + "weabot.txt", "w")
+ logfile.write(logTimes())
+ logfile.close()
+
+ def __iter__(self):
+ self.handleResponse()
+ self.start("200 OK", self.headers)
+ yield self.output
+
+ def error(self, message):
+ board = Settings._.BOARD
+ if board:
+ if board['board_type'] == '1':
+ info = {}
+ info['host'] = self.environ["REMOTE_ADDR"]
+ info['name'] = self.formdata.get('fielda', '')
+ info['email'] = self.formdata.get('fieldb', '')
+ info['message'] = self.formdata.get('message', '')
+
+ self.output += renderTemplate("txt_error.html",
+ {"info": info, "error": message})
+ else:
+ mobile = self.formdata.get('mobile', '')
+ if mobile:
+ self.output += renderTemplate("mobile/error.html",
+ {"error": message})
+ else:
+ self.output += renderTemplate("error.html", {
+ "error": message, "boards_url": Settings.BOARDS_URL, "board": board["dir"]})
else:
- self.output = threadPage(path_split[3], True)
- elif path_split[1] == "catalog":
- OpenDb()
- board = setBoard(path_split[2])
- caught = True
- sort = self.formdata.get('sort', '')
- self.output = catalog(sort)
- elif path_split[1] == "oekaki":
- caught = True
- OpenDb()
- oekaki.oekaki(self, path_split)
- elif path_split[1] == "play":
- # Module player
- caught = True
- boarddir = path_split[2]
- modfile = path_split[3]
- self.output = renderTemplate('mod.html', {'board': boarddir, 'modfile': modfile})
- elif path_split[1] == "report":
- # Report post, check if they are enabled
- # Can't report if banned
- caught = True
- ip = self.environ["REMOTE_ADDR"]
- boarddir = path_split[2]
- postid = int(path_split[3])
- reason = self.formdata.get('reason')
- try:
- txt = True
- postshow = int(path_split[4])
- except:
- txt = False
- postshow = postid
-
- self.report(ip, boarddir, postid, reason, txt, postshow)
- elif path_split[1] == "stats":
- caught = True
- self.stats()
- elif path_split[1] == "random":
- caught = True
+ self.output += renderTemplate("exception.html",
+ {"exception": None, "error": message})
+
+ def exception(self, type, message, detail):
+ self.output += renderTemplate("exception.html",
+ {"exception": type, "error": message, "detail": detail})
+
+ def handleRequest(self):
+ self.headers = [("Content-Type", "text/html")]
+ self.handleCookies()
+
+ def handleResponse(self):
+ if self._newcookies:
+ for newcookie in self._newcookies.values():
+ self.headers.append(
+ ("Set-Cookie", newcookie.output(header="")))
+
+ def handleCookies(self):
+ self._cookies = SimpleCookie()
+ self._cookies.load(self.environ.get("HTTP_COOKIE", ""))
+ self._newcookies = None
+
+ def run(self):
+ path_split = self.environ["PATH_INFO"].split("/")
+ caught = False
+
+ if Settings.FULL_MAINTENANCE:
+ raise UserError, _(
+ "%s is currently under maintenance. We'll be back.") % Settings.SITE_TITLE
+
+ if len(path_split) > 1:
+ if path_split[1] == "post":
+ # Making a post
+ caught = True
+
+ if 'password' not in self.formdata:
+ raise UserError, "El request está incompleto."
+
+ # let's get all the POST data we need
+ ip = self.environ["REMOTE_ADDR"]
+ boarddir = self.formdata.get('board')
+ parent = self.formdata.get('parent')
+ trap1 = self.formdata.get('name', '')
+ trap2 = self.formdata.get('email', '')
+ name = self.formdata.get('fielda', '')
+ email = self.formdata.get('fieldb', '')
+ subject = self.formdata.get('subject', '')
+ message = self.formdata.get('message', '')
+ file = self.formdata.get('file')
+ file_original = self.formdata.get('file_original')
+ spoil = self.formdata.get('spoil')
+ oek_file = self.formdata.get('oek_file')
+ password = self.formdata.get('password', '')
+ noimage = self.formdata.get('noimage')
+ mobile = ("mobile" in self.formdata.keys())
+
+ # call post function
+ (post_url, ttaken, unused) = self.make_post(ip, boarddir, parent, trap1, trap2, name,
+ email, subject, message, file, file_original, spoil, oek_file, password, noimage, mobile)
+
+ # make redirect
+ self.output += make_redirect(post_url, ttaken)
+ elif path_split[1] == "environ":
+ caught = True
+
+ self.output += repr(self.environ)
+ elif path_split[1] == "delete":
+ # Deleting a post
+ caught = True
+
+ boarddir = self.formdata.get('board')
+ postid = self.formdata.get('delete')
+ imageonly = self.formdata.get('imageonly')
+ password = self.formdata.get('password')
+ mobile = self.formdata.get('mobile')
+
+ # call delete function
+ self.delete_post(boarddir, postid, imageonly, password, mobile)
+ elif path_split[1] == "anarkia":
+ import anarkia
+ caught = True
+ OpenDb()
+ anarkia.anarkia(self, path_split)
+ elif path_split[1] == "manage":
+ caught = True
+ OpenDb()
+ manage.manage(self, path_split)
+ elif path_split[1] == "api":
+ import api
+ caught = True
+ self.headers = [("Content-Type", "application/json"), ("Access-Control-Allow-Origin", "*"), ("Access-Control-Allow-Methods",
+ "PUT, GET, POST, DELETE, OPTIONS"), ("Access-Control-Allow-Headers", "Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With")]
+ OpenDb()
+ api.api(self, path_split)
+ elif path_split[1] == "threadlist":
+ OpenDb()
+ board = setBoard(path_split[2])
+ caught = True
+ if board['board_type'] != '1':
+ raise UserError, "No disponible para esta sección."
+ self.output = threadList(0)
+ elif path_split[1] == "mobile":
+ OpenDb()
+ board = setBoard(path_split[2])
+ caught = True
+ self.output = threadList(1)
+ elif path_split[1] == "mobilelist":
+ OpenDb()
+ board = setBoard(path_split[2])
+ caught = True
+ self.output = threadList(2)
+ elif path_split[1] == "mobilecat":
+ OpenDb()
+ board = setBoard(path_split[2])
+ caught = True
+ self.output = threadList(3)
+ elif path_split[1] == "mobilenew":
+ OpenDb()
+ board = setBoard(path_split[2])
+ caught = True
+ self.output = renderTemplate('txt_newthread.html', {}, True)
+ elif path_split[1] == "mobilehome":
+ OpenDb()
+ latest_age = getLastAge(Settings.HOME_LASTPOSTS)
+ for threads in latest_age:
+ content = threads['url']
+ content = content.replace('/read/', '/')
+ content = content.replace('/res/', '/')
+ content = content.replace('.html', '')
+ threads['url'] = content
+ caught = True
+ self.output = renderTemplate(
+ 'latest.html', {'latest_age': latest_age}, True)
+ elif path_split[1] == "mobilenewest":
+ OpenDb()
+ newthreads = getNewThreads(Settings.HOME_LASTPOSTS)
+ for threads in newthreads:
+ content = threads['url']
+ content = content.replace('/read/', '/')
+ content = content.replace('/res/', '/')
+ content = content.replace('.html', '')
+ threads['url'] = content
+ caught = True
+ self.output = renderTemplate(
+ 'newest.html', {'newthreads': newthreads}, True)
+ elif path_split[1] == "mobileread":
+ OpenDb()
+ board = setBoard(path_split[2])
+ caught = True
+ 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])
+ else:
+ self.output = threadPage(path_split[3], True)
+ elif path_split[1] == "catalog":
+ OpenDb()
+ board = setBoard(path_split[2])
+ caught = True
+ sort = self.formdata.get('sort', '')
+ self.output = catalog(sort)
+ elif path_split[1] == "oekaki":
+ caught = True
+ OpenDb()
+ oekaki.oekaki(self, path_split)
+ elif path_split[1] == "play":
+ # Module player
+ caught = True
+ boarddir = path_split[2]
+ modfile = path_split[3]
+ self.output = renderTemplate(
+ 'mod.html', {'board': boarddir, 'modfile': modfile})
+ elif path_split[1] == "report":
+ # Report post, check if they are enabled
+ # Can't report if banned
+ caught = True
+ ip = self.environ["REMOTE_ADDR"]
+ boarddir = path_split[2]
+ postid = int(path_split[3])
+ reason = self.formdata.get('reason')
+ try:
+ txt = True
+ postshow = int(path_split[4])
+ except:
+ txt = False
+ postshow = postid
+
+ self.report(ip, boarddir, postid, reason, txt, postshow)
+ elif path_split[1] == "stats":
+ caught = True
+ self.stats()
+ elif path_split[1] == "random":
+ 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'] + '/'
+ else:
+ url = 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'] + '/'
+ 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()
+ packed_ip = inet_aton(self.environ["REMOTE_ADDR"])
+ bans = FetchAll("SELECT * FROM `bans` WHERE (`netmask` IS NULL AND `ip` = '"+str(
+ packed_ip)+"') OR (`netmask` IS NOT NULL AND '"+str(packed_ip)+"' & `netmask` = `ip`)")
+ if bans:
+ for ban in bans:
+ if ban["boards"] != "":
+ boards = pickle.loads(ban["boards"])
+ if ban["boards"] == "" or path_split[2] in boards:
+ caught = True
+ if ban["boards"]:
+ boards_str = '/' + '/, /'.join(boards) + '/'
+ else:
+ boards_str = _("all boards")
+ if ban["until"] != "0":
+ expire = formatTimestamp(ban["until"])
+ else:
+ expire = ""
+
+ template_values = {
+ # 'return_board': path_split[2],
+ 'boards_str': boards_str,
+ 'reason': ban['reason'],
+ 'added': formatTimestamp(ban["added"]),
+ 'expire': expire,
+ 'ip': self.environ["REMOTE_ADDR"],
+ }
+ self.output = renderTemplate(
+ 'banned.html', template_values)
+ else:
+ if len(path_split) > 2:
+ caught = True
+ self.output += '<html xmlns="http://www.w3.org/1999/xhtml"><body><meta http-equiv="refresh" content="0;url=%s" /><p>%s</p></body></html>' % (
+ Settings.HOME_URL + path_split[2], _("Your ban has expired. Redirecting..."))
+ elif path_split[1] == "read":
+ # Textboard read:
+ if len(path_split) > 4:
+ caught = True
+ # 2: board
+ # 3: thread
+ # 4: post(s)
+ OpenDb()
+ board = setBoard(path_split[2])
+ self.output = dynamicRead(
+ int(path_split[3]), path_split[4])
+ elif path_split[1] == "preview":
+ caught = True
+ OpenDb()
+ try:
+ board = setBoard(self.formdata["board"])
+ message = format_post(
+ self.formdata["message"], self.environ["REMOTE_ADDR"], self.formdata["parentid"])
+ self.output = message
+ except Exception, messagez:
+ self.output = "Error: " + \
+ str(messagez) + " : " + str(self.formdata)
+ if not caught:
+ # 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>--&gt; --&gt; --&gt;</p></body></html>' % Settings.HOME_URL
+
+ 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
+
+ if addressIsUS(ip):
+ raise UserError, "Host en lista negra."
+
+ # open database
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'])
+
+ # set the board
+ board = setBoard(boarddir)
+
+ if board["dir"] != ["anarkia"]:
+ if addressIsProxy(ip):
+ raise UserError, "Proxy prohibido en esta sección."
+
+ # check length of fields
+ if len(name) > 50:
+ raise UserError, "El campo de nombre es muy largo."
+ if len(email) > 50:
+ raise UserError, "El campo de e-mail es muy largo."
+ if len(subject) > 100:
+ raise UserError, "El campo de asunto es muy largo."
+ if len(message) > 8000:
+ raise UserError, "El campo de mensaje es muy largo."
+ if message.count('\n') > 50:
+ 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."
+
+ # Create a single datetime now so everything syncs up
+ t = time.time()
+
+ # Delete expired bans
+ deletedBans = UpdateDb(
+ "DELETE FROM `bans` WHERE `until` != 0 AND `until` < " + str(timestamp()))
+ if deletedBans > 0:
+ regenerateAccess()
+
+ # Redirect to ban page if user is banned
+ if addressIsBanned(ip, board["dir"]):
+ #raise UserError, 'Tu host está en la lista negra.'
+ 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:
+ 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.")
+
+ # create post object
+ post = Post(board["id"])
+ post["ip"] = inet_aton(ip)
+ post["timestamp"] = post["bumped"] = int(t)
+ post["timestamp_formatted"] = formatTimestamp(t)
+
+ # load parent info if we are replying
+ parent_post = None
+ parent_timestamp = post["timestamp"]
+ if parent:
+ parent_post = get_parent_post(parent, board["id"])
+ parent_timestamp = parent_post['timestamp']
+ 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.")
+
+ # check if the user is flooding
+ flood_check(t, post, board["id"])
+
+ # use fields only if enabled
+ if board["disable_name"] != '1':
+ post["name"] = cleanString(name)
+ post["email"] = cleanString(email, quote=True)
+ if board["disable_subject"] != '1':
+ post["subject"] = cleanString(subject)
+
+ # process tripcodes
+ post["name"], post["tripcode"] = tripcode(post["name"])
+
+ # Remove carriage return, they're useless
+ message = message.replace("\r", "")
+
+ # check ! functions before
+ extend = extend_str = dice = ball = None
+
+ if not post["parentid"] and board["dir"] not in ['bai', 'world']:
+ # creating thread
+ __extend = re.compile(r"^!extend(:\w+)(:\w+)?\n")
+ res = __extend.match(message)
+ if res:
+ extend = res.groups()
+ # truncate extend
+ extend_str = res.group(0)
+ message = message[res.end(0):]
+
+ if board["dir"] in ['juegos', '0', 'polka']:
+ __dice = re.compile(r"^!dado(:\w+)(:\w+)?\n")
+ res = __dice.match(message)
+ if res:
+ dice = res.groups()
+ message = message[res.end(0):]
+
+ if board["dir"] in ['zonavip', '0', 'polka']:
+ __ball = re.compile(r"^!bola8\n")
+ res = __ball.match(message)
+ if res:
+ ball = True
+ message = message[res.end(0):]
+
+ # use and format message
+ if message.strip():
+ post["message"] = format_post(
+ message, ip, post["parentid"], parent_timestamp)
+
+ # add function messages
+ if extend_str:
+ extend_str = extend_str.replace('!extend', 'EXTEND')
+ post["message"] += '<hr />' + extend_str + ' configurado.'
+ if dice:
+ post["message"] += '<hr />' + throw_dice(dice)
+ if ball:
+ post["message"] += '<hr />' + magic_ball()
+
+ if not post["parentid"] and post["email"].lower() == 'sage':
+ post["email"] = ""
+
+ # disallow illegal characters
+ if post["name"]:
+ post["name"] = post["name"].replace('★', '☆')
+ post["name"] = post["name"].replace('◆', '◇')
+
+ # process capcodes
+ cap_id = hide_end = None
+ if post["name"] in Settings.CAPCODES:
+ capcode = Settings.CAPCODES[post["name"]]
+ if post["tripcode"] == (Settings.TRIP_CHAR + capcode[0]):
+ post["name"], post["tripcode"] = capcode[1], capcode[2]
+ # if board['board_type'] == '1':
+ # post["name"], post["tripcode"] = capcode[1], ''
+ # else:
+ # post["name"] = post["tripcode"] = ''
+ # post["message"] = ('[<span style="color:red">%s</span>]<br />' % capcode[2]) + post["message"]
+
+ cap_id, hide_end = capcode[3], capcode[4]
+
+ # hide ip if necessary
+ if hide_end:
+ post["ip"] = 0
+
+ # use password
+ post["password"] = password
+
+ # EXTEND feature
+ if post["parentid"] and board["dir"] not in ['bai', 'world']:
+ # replying
+ __extend = re.compile(r"<hr />EXTEND(:\w+)(:\w+)?\b")
+ res = __extend.search(parent_post["message"])
+ if res:
+ extend = res.groups()
+
+ # compatibility : old id function
+ if 'id' in parent_post["email"]:
+ board["useid"] = '3'
+
+ if 'id' in post["email"]:
+ board["useid"] = '3'
+
+ if extend:
+ try:
+ # 1: ID
+ if extend[0] == ':no':
+ board["useid"] = '0'
+ elif extend[0] == ':yes':
+ board["useid"] = '1'
+ elif extend[0] == ':force':
+ board["useid"] = '2'
+ elif extend[0] == ':extra':
+ board["useid"] = '3'
+
+ # 2: Slip
+ if extend[1] == ':no':
+ board["slip"] = '0'
+ elif extend[1] == ':yes':
+ board["slip"] = '1'
+ elif extend[1] == ':domain':
+ board["slip"] = '2'
+ elif extend[1] == ':verbose':
+ board["slip"] = '3'
+ elif extend[1] == ':country':
+ board["countrycode"] = '1'
+ elif extend[1] == ':all':
+ board["slip"] = '3'
+ board["countrycode"] = '1'
+ except IndexError:
+ pass
+
+ # if we are replying, use first post's time
+ if post["parentid"]:
+ tim = parent_post["timestamp"]
+ else:
+ tim = post["timestamp"]
+
+ # make ID hash
+ if board["useid"] != '0':
+ 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)
+
+ # textboard inforcements (change it to settings maybe?)
if board['board_type'] == '1':
- url = Settings.HOME_URL + board['dir'] + '/read/' + thread['timestamp'] + '/'
+ if not post["parentid"] and not post["subject"]:
+ raise UserError, _(
+ "You must enter a title to create a thread.")
+ if not post["message"]:
+ raise UserError, _("Please enter a message.")
else:
- url = 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'] + '/'
- 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()
- packed_ip = inet_aton(self.environ["REMOTE_ADDR"])
- bans = FetchAll("SELECT * FROM `bans` WHERE (`netmask` IS NULL AND `ip` = '"+str(packed_ip)+"') OR (`netmask` IS NOT NULL AND '"+str(packed_ip)+"' & `netmask` = `ip`)")
- if bans:
- for ban in bans:
- if ban["boards"] != "":
- boards = pickle.loads(ban["boards"])
- if ban["boards"] == "" or path_split[2] in boards:
- caught = True
- if ban["boards"]:
- boards_str = '/' + '/, /'.join(boards) + '/'
- else:
- boards_str = _("all boards")
- if ban["until"] != "0":
- expire = formatTimestamp(ban["until"])
- else:
- expire = ""
-
- template_values = {
- #'return_board': path_split[2],
- 'boards_str': boards_str,
- 'reason': ban['reason'],
- 'added': formatTimestamp(ban["added"]),
- 'expire': expire,
- 'ip': self.environ["REMOTE_ADDR"],
- }
- self.output = renderTemplate('banned.html', template_values)
+ if not post["parentid"] and not xfile and not noimage:
+ 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.")
+
+ # check if this post is allowed
+ if post["parentid"]:
+ if file and board['allow_image_replies'] == '0':
+ raise UserError, _("Image replies not allowed.")
else:
- if len(path_split) > 2:
- caught = True
- self.output += '<html xmlns="http://www.w3.org/1999/xhtml"><body><meta http-equiv="refresh" content="0;url=%s" /><p>%s</p></body></html>' % (Settings.HOME_URL + path_split[2], _("Your ban has expired. Redirecting..."))
- elif path_split[1] == "read":
- # Textboard read:
- if len(path_split) > 4:
- caught = True
- # 2: board
- # 3: thread
- # 4: post(s)
- OpenDb()
- board = setBoard(path_split[2])
- self.output = dynamicRead(int(path_split[3]), path_split[4])
- elif path_split[1] == "preview":
- caught = True
+ if file and board['allow_images'] == '0':
+ 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'):
+ post["name"] = random.choice(board["anonymous"].split('|'))
+ if (not post["subject"] and not post["parentid"]) or (post["subject"].lower() == 'sage'):
+ post["subject"] = board["subject"]
+ if not post["message"]:
+ post["message"] = board["message"]
+
+ # process files
+ if oek_file:
+ try:
+ fname = os.path.join(Settings.IMAGES_DIR,
+ board['dir'], "temp", oek_file + ".png")
+ with open(fname, 'rb') as f:
+ file = f.read()
+ except:
+ raise UserError, "Imposible leer la imagen oekaki."
+
+ if file and not noimage:
+ post = processImage(post, file, t, file_original,
+ (spoil and board['allow_spoilers'] == '1'))
+
+ if oek_file:
+ # Remove temporary oekaki file if everything went right
+ # os.remove(fname)
+ # TODO: We will rename the file for now. We don't want lost work.
+ try:
+ os.rename(fname, fname + ".bak")
+ except:
+ pass # Just keep it if anything went wrong
+
+ # slip
+ if board["slip"] != '0':
+ slips = []
+
+ # name
+ 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:
+ host_nick = 'sarin'
+
+ if hide_end:
+ host_nick = '★'
+ elif addressIsTor(ip):
+ host_nick = 'onion'
+ else:
+ isps = {'cablevision': 'easy',
+ 'cantv': 'warrior',
+ 'claro': 'america',
+ 'cnet': 'nova',
+ 'copelnet': 'cisneros',
+ 'cps.com': 'silver',
+ 'cybercable': 'bricklayer',
+ 'entel': 'matte',
+ 'eternet': 'stream',
+ 'fibertel': 'roughage',
+ 'geonet': 'thunder',
+ 'gtdinternet': 'casanueva',
+ 'ifxnw': 'effect',
+ 'infinitum': 'telegraph',
+ 'intercable': 'easy',
+ 'intercity': 'cordoba',
+ 'iplannet': 'conquest',
+ 'itcsa.net': 'sarmiento',
+ 'megared': 'clear',
+ 'movistar': 'bell',
+ 'nextel': 'fleet',
+ 'speedy': 'oxygen',
+ 'telecom': 'license',
+ 'telmex': 'slender',
+ 'telnor': 'compass',
+ 'tie.cl': 'bell',
+ 'vtr.net': 'liberty',
+ 'utfsm': 'virgin',
+ }
+ host = getHost(ip)
+
+ if host:
+ for k, v in isps.iteritems():
+ if k in host:
+ host_nick = v
+ break
+
+ slips.append(host_nick)
+
+ # hash
+ if board["slip"] in ['1', '3']:
+ if hide_end:
+ slips.append('-'.join(('****', '****')))
+ elif addressIsTor(ip):
+ slips.append(
+ '-'.join(('****', getMD5(self.environ["HTTP_USER_AGENT"])[:4])))
+ else:
+ slips.append(
+ '-'.join((getMD5(ip)[:4], getMD5(self.environ["HTTP_USER_AGENT"])[:4])))
+
+ # host
+ if board["slip"] == '2':
+ if hide_end:
+ host = '★'
+ elif addressIsTor(ip):
+ host = 'onion'
+ else:
+ host = getHost(ip)
+ if host:
+ hosts = host.split('.')
+ if len(hosts) > 2:
+ if hosts[-2] in ['ne', 'net', 'com', 'co']:
+ host = '.'.join(
+ (hosts[-3], hosts[-2], hosts[-1]))
+ else:
+ host = '.'.join((hosts[-2], hosts[-1]))
+ host = '*.' + host
+ else:
+ iprs = ip.split('.')
+ host = '%s.%s.*.*' % (iprs[0], iprs[1])
+ slips.append(host)
+
+ # IP
+ if board["slip"] == '3':
+ if hide_end:
+ host = '[*.*.*.*]'
+ else:
+ iprs = ip.split('.')
+ host = '[%s.%s.*.*]' % (iprs[0], iprs[1])
+ slips.append(host)
+
+ if slips:
+ post["tripcode"] += " (%s)" % ' '.join(slips)
+
+ # country code
+ if board["countrycode"] == '1':
+ if hide_end or addressIsTor(ip):
+ country = '??'
+ else:
+ country = getCountry(ip)
+ post["name"] += " <em>[%s]</em>" % country
+
+ # set expiration date if necessary
+ 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:
+ date_format = date_format_y
+ post["expires_formatted"] = datetime.datetime.fromtimestamp(
+ post["expires"]).strftime(date_format)
+
+ if not post["parentid"]:
+ # fill with default values if creating a new thread
+ post["length"] = 1
+ post["last"] = post["timestamp"]
+
+ 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."
+
+ # insert icon if needed
+ img_src = '<img src="%s" alt="ico" /><br />' % getRandomIco()
+ post["message"] = img_src + post["message"]
+
+ # insert post, then run timThreads to make sure the board doesn't exceed the page limit
+ postid = post.insert()
+
+ # delete threads that have crossed last page
+ trimThreads()
+
+ # fix null references when creating thread
+ 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))))
+
+ # do operations if replying to a thread (bump, autoclose, update cache)
+ logTime("Updating thread")
+ thread_length = None
+ if post["parentid"]:
+ # get length of the thread
+ thread_length = threadNumReplies(post["parentid"])
+
+ # 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"]))
+
+ # 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"]))
+
+ # update cache
+ threadUpdated(post["parentid"])
+ else:
+ # create cache for new thread
+ threadUpdated(postid)
+
+ regenerateHome()
+
+ # make page redirect
+ ttaken = timeTaken(_STARTTIME, time.clock())
+ 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':
+ # add to recent posts
+ if Settings.ENABLE_RSS:
+ latestAdd(post, thread_length, postid, parent_post)
+ # call discord hook
+ if Settings.ENABLE_DISCORD_HOOK and not post["parentid"]:
+ hook_url = make_url(
+ postid, post, parent_post or post, True, False)
+ discord_hook(post, hook_url)
+
+ return (post_url, ttaken, postid)
+
+ def delete_post(self, boarddir, postid, imageonly, password, mobile=False):
OpenDb()
- try:
- board = setBoard(self.formdata["board"])
- message = format_post(self.formdata["message"], self.environ["REMOTE_ADDR"], self.formdata["parentid"])
- self.output = message
- except Exception, messagez:
- self.output = "Error: " + str(messagez) + " : " + str(self.formdata)
- if not caught:
- # 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>--&gt; --&gt; --&gt;</p></body></html>' % Settings.HOME_URL
-
- 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
-
- if addressIsUS(ip):
- raise UserError, "Host en lista negra."
-
- # open database
- OpenDb()
-
- # set the board
- board = setBoard(boarddir)
-
- if board["dir"] != ["anarkia"]:
- if addressIsProxy(ip):
- raise UserError, "Proxy prohibido en esta sección."
-
- # check length of fields
- if len(name) > 50:
- raise UserError, "El campo de nombre es muy largo."
- if len(email) > 50:
- raise UserError, "El campo de e-mail es muy largo."
- if len(subject) > 100:
- raise UserError, "El campo de asunto es muy largo."
- if len(message) > 8000:
- raise UserError, "El campo de mensaje es muy largo."
- if message.count('\n') > 50:
- 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."
-
- # Create a single datetime now so everything syncs up
- t = time.time()
-
- # Delete expired bans
- deletedBans = UpdateDb("DELETE FROM `bans` WHERE `until` != 0 AND `until` < " + str(timestamp()))
- if deletedBans > 0:
- regenerateAccess()
-
- # Redirect to ban page if user is banned
- if addressIsBanned(ip, board["dir"]):
- #raise UserError, 'Tu host está en la lista negra.'
- 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:
- 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.")
-
- # create post object
- post = Post(board["id"])
- post["ip"] = inet_aton(ip)
- post["timestamp"] = post["bumped"] = int(t)
- post["timestamp_formatted"] = formatTimestamp(t)
-
- # load parent info if we are replying
- parent_post = None
- parent_timestamp = post["timestamp"]
- if parent:
- parent_post = get_parent_post(parent, board["id"])
- parent_timestamp = parent_post['timestamp']
- 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.")
-
- # check if the user is flooding
- flood_check(t, post, board["id"])
-
- # use fields only if enabled
- if board["disable_name"] != '1':
- post["name"] = cleanString(name)
- post["email"] = cleanString(email, quote=True)
- if board["disable_subject"] != '1':
- post["subject"] = cleanString(subject)
-
- # process tripcodes
- post["name"], post["tripcode"] = tripcode(post["name"])
-
- # Remove carriage return, they're useless
- message = message.replace("\r", "")
-
- # check ! functions before
- extend = extend_str = dice = ball = None
-
- if not post["parentid"] and board["dir"] not in ['bai', 'world']:
- # creating thread
- __extend = re.compile(r"^!extend(:\w+)(:\w+)?\n")
- res = __extend.match(message)
- if res:
- extend = res.groups()
- # truncate extend
- extend_str = res.group(0)
- message = message[res.end(0):]
-
- if board["dir"] in ['juegos', '0', 'polka']:
- __dice = re.compile(r"^!dado(:\w+)(:\w+)?\n")
- res = __dice.match(message)
- if res:
- dice = res.groups()
- message = message[res.end(0):]
-
- if board["dir"] in ['zonavip', '0', 'polka']:
- __ball = re.compile(r"^!bola8\n")
- res = __ball.match(message)
- if res:
- ball = True
- message = message[res.end(0):]
-
- # use and format message
- if message.strip():
- post["message"] = format_post(message, ip, post["parentid"], parent_timestamp)
-
- # add function messages
- if extend_str:
- extend_str = extend_str.replace('!extend', 'EXTEND')
- post["message"] += '<hr />' + extend_str + ' configurado.'
- if dice:
- post["message"] += '<hr />' + throw_dice(dice)
- if ball:
- post["message"] += '<hr />' + magic_ball()
-
- if not post["parentid"] and post["email"].lower() == 'sage':
- post["email"] = ""
-
- # disallow illegal characters
- if post["name"]:
- post["name"] = post["name"].replace('★', '☆')
- post["name"] = post["name"].replace('◆', '◇')
-
- # process capcodes
- cap_id = hide_end = None
- if post["name"] in Settings.CAPCODES:
- capcode = Settings.CAPCODES[post["name"]]
- if post["tripcode"] == (Settings.TRIP_CHAR + capcode[0]):
- post["name"], post["tripcode"] = capcode[1], capcode[2]
- #if board['board_type'] == '1':
- # post["name"], post["tripcode"] = capcode[1], ''
- #else:
- # post["name"] = post["tripcode"] = ''
- # post["message"] = ('[<span style="color:red">%s</span>]<br />' % capcode[2]) + post["message"]
-
- cap_id, hide_end = capcode[3], capcode[4]
-
- # hide ip if necessary
- if hide_end:
- post["ip"] = 0
-
- # use password
- post["password"] = password
-
- # EXTEND feature
- if post["parentid"] and board["dir"] not in ['bai', 'world']:
- # replying
- __extend = re.compile(r"<hr />EXTEND(:\w+)(:\w+)?\b")
- res = __extend.search(parent_post["message"])
- if res:
- extend = res.groups()
-
- # compatibility : old id function
- if 'id' in parent_post["email"]:
- board["useid"] = '3'
-
- if 'id' in post["email"]:
- board["useid"] = '3'
-
- if extend:
- try:
- # 1: ID
- if extend[0] == ':no':
- board["useid"] = '0'
- elif extend[0] == ':yes':
- board["useid"] = '1'
- elif extend[0] == ':force':
- board["useid"] = '2'
- elif extend[0] == ':extra':
- board["useid"] = '3'
-
- # 2: Slip
- if extend[1] == ':no':
- board["slip"] = '0'
- elif extend[1] == ':yes':
- board["slip"] = '1'
- elif extend[1] == ':domain':
- board["slip"] = '2'
- elif extend[1] == ':verbose':
- board["slip"] = '3'
- elif extend[1] == ':country':
- board["countrycode"] = '1'
- elif extend[1] == ':all':
- board["slip"] = '3'
- board["countrycode"] = '1'
- except IndexError:
- pass
-
- # if we are replying, use first post's time
- if post["parentid"]:
- tim = parent_post["timestamp"]
- else:
- tim = post["timestamp"]
-
- # make ID hash
- if board["useid"] != '0':
- 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)
-
- # textboard inforcements (change it to settings maybe?)
- if board['board_type'] == '1':
- if not post["parentid"] and not post["subject"]:
- raise UserError, _("You must enter a title to create a thread.")
- if not post["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.")
- if not xfile and not post["message"]:
- 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.")
- else:
- if file and board['allow_images'] == '0':
- 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'):
- post["name"] = random.choice(board["anonymous"].split('|'))
- if (not post["subject"] and not post["parentid"]) or (post["subject"].lower() == 'sage'):
- post["subject"] = board["subject"]
- if not post["message"]:
- post["message"] = board["message"]
-
- # process files
- if oek_file:
- try:
- fname = os.path.join(Settings.IMAGES_DIR, board['dir'], "temp", oek_file + ".png")
- with open(fname, 'rb') as f:
- file = f.read()
- except:
- raise UserError, "Imposible leer la imagen oekaki."
-
- if file and not noimage:
- post = processImage(post, file, t, file_original, (spoil and board['allow_spoilers'] == '1'))
-
- if oek_file:
- # Remove temporary oekaki file if everything went right
- #os.remove(fname)
- # TODO: We will rename the file for now. We don't want lost work.
- try:
- os.rename(fname, fname + ".bak")
- except:
- pass # Just keep it if anything went wrong
-
- # slip
- if board["slip"] != '0':
- slips = []
-
- # name
- 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'
+
+ # set the board
+ board = setBoard(boarddir)
+
+ if board["dir"] == '0':
+ 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."
+
+ # make sure we have a password
+ if not password:
+ raise UserError, _("Please enter a password.")
+
+ to_delete = []
+ if isinstance(postid, list):
+ to_delete = [n.value for n in postid]
else:
- host_nick = 'sarin'
-
- if hide_end:
- host_nick = '★'
- elif addressIsTor(ip):
- host_nick = 'onion'
- else:
- isps = {'cablevision': 'easy',
- 'cantv': 'warrior',
- 'claro': 'america',
- 'cnet': 'nova',
- 'copelnet': 'cisneros',
- 'cps.com': 'silver',
- 'cybercable': 'bricklayer',
- 'entel': 'matte',
- 'eternet': 'stream',
- 'fibertel': 'roughage',
- 'geonet': 'thunder',
- 'gtdinternet': 'casanueva',
- 'ifxnw': 'effect',
- 'infinitum': 'telegraph',
- 'intercable': 'easy',
- 'intercity': 'cordoba',
- 'iplannet': 'conquest',
- 'itcsa.net': 'sarmiento',
- 'megared': 'clear',
- 'movistar': 'bell',
- 'nextel': 'fleet',
- 'speedy': 'oxygen',
- 'telecom': 'license',
- 'telmex': 'slender',
- 'telnor': 'compass',
- 'tie.cl': 'bell',
- 'vtr.net': 'liberty',
- 'utfsm': 'virgin',
- }
- host = getHost(ip)
-
- if host:
- for k, v in isps.iteritems():
- if k in host:
- host_nick = v
- break
-
- slips.append(host_nick)
-
- # hash
- if board["slip"] in ['1', '3']:
- if hide_end:
- slips.append('-'.join(('****', '****')))
- elif addressIsTor(ip):
- slips.append('-'.join(('****', getMD5(self.environ["HTTP_USER_AGENT"])[:4])))
+ to_delete = [postid]
+
+ # delete posts
+ 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'
+ 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':
+ op = get_parent_post(post['parentid'], board['id'])
+ if op['last'] != post['timestamp']:
+ deltype = '1'
+
+ deletePost(to_delete[0], password, deltype, imageonly)
+ latestRemove(post['id'])
+ regenerateHome()
else:
- slips.append('-'.join((getMD5(ip)[:4], getMD5(self.environ["HTTP_USER_AGENT"])[:4])))
-
- # host
- if board["slip"] == '2':
- if hide_end:
- host = '★'
- elif addressIsTor(ip):
- host = 'onion'
+ # delete all checked posts (IB)
+ deleted = 0
+ errors = 0
+ msgs = []
+
+ for pid in to_delete:
+ try:
+ deletePost(pid, password, board['recyclebin'], imageonly)
+ latestRemove(pid)
+ deleted += 1
+ msgs.append('No.%s: Eliminado' % pid)
+ except UserError, message:
+ errors += 1
+ msgs.append('No.%s: %s' % (pid, message))
+
+ # regenerate home
+ if deleted:
+ regenerateHome()
+
+ # show errors, if any
+ if errors:
+ raise UserError, 'No todos los mensajes pudieron ser eliminados.<br />' + \
+ '<br />'.join(msgs)
+
+ # redirect
+ if imageonly:
+ self.output += '<html xmlns="http://www.w3.org/1999/xhtml"><body><meta http-equiv="refresh" content="0;url=%s/" /><p>%s</p></body></html>' % (
+ ("/cgi/mobile/" if mobile else Settings.BOARDS_URL) + board["dir"], _("File deleted successfully."))
else:
- host = getHost(ip)
- if host:
- hosts = host.split('.')
- if len(hosts) > 2:
- if hosts[-2] in ['ne', 'net', 'com', 'co']:
- host = '.'.join((hosts[-3], hosts[-2], hosts[-1]))
- else:
- host = '.'.join((hosts[-2], hosts[-1]))
- host = '*.' + host
- else:
- iprs = ip.split('.')
- host = '%s.%s.*.*' % (iprs[0], iprs[1])
- slips.append(host)
-
- # IP
- if board["slip"] == '3':
- if hide_end:
- host = '[*.*.*.*]'
+ self.output += '<html xmlns="http://www.w3.org/1999/xhtml"><body><meta http-equiv="refresh" content="0;url=%s/" /><p>%s</p></body></html>' % (
+ ("/cgi/mobile/" if mobile else Settings.BOARDS_URL) + board["dir"], _("Post deleted successfully."))
+
+ 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.')
+
+ # if there's not a reason, show the report page
+ if reason is None:
+ self.output += renderTemplate("report.html",
+ {'finished': False, 'postshow': postshow, 'txt': txt})
+ return
+
+ # check reason
+ if not reason:
+ raise UserError, _("Enter a reason.")
+ if len(reason) > 100:
+ raise UserError, _("Text too long.")
+
+ # open database
+ OpenDb()
+
+ # set the board we're in
+ board = setBoard(boarddir)
+
+ # check if he's banned
+ if 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.")
+
+ # generate link
+ 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)
else:
- iprs = ip.split('.')
- host = '[%s.%s.*.*]' % (iprs[0], iprs[1])
- slips.append(host)
-
- if slips:
- post["tripcode"] += " (%s)" % ' '.join(slips)
-
- # country code
- if board["countrycode"] == '1':
- if hide_end or addressIsTor(ip):
- country = '??'
- else:
- country = getCountry(ip)
- post["name"] += " <em>[%s]</em>" % country
-
- # set expiration date if necessary
- 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:
- date_format = date_format_y
- post["expires_formatted"] = datetime.datetime.fromtimestamp(post["expires"]).strftime(date_format)
-
- if not post["parentid"]:
- # fill with default values if creating a new thread
- post["length"] = 1
- post["last"] = post["timestamp"]
-
- 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."
-
- # insert icon if needed
- img_src = '<img src="%s" alt="ico" /><br />' % getRandomIco()
- post["message"] = img_src + post["message"]
-
- # insert post, then run timThreads to make sure the board doesn't exceed the page limit
- postid = post.insert()
-
- # delete threads that have crossed last page
- trimThreads()
-
- # fix null references when creating thread
- 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))))
-
- # do operations if replying to a thread (bump, autoclose, update cache)
- logTime("Updating thread")
- thread_length = None
- if post["parentid"]:
- # get length of the thread
- thread_length = threadNumReplies(post["parentid"])
-
- # 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"]))
-
- # 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"]))
-
- # update cache
- threadUpdated(post["parentid"])
- else:
- # create cache for new thread
- threadUpdated(postid)
-
- regenerateHome()
-
- # make page redirect
- ttaken = timeTaken(_STARTTIME, time.clock())
- 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':
- # add to recent posts
- if Settings.ENABLE_RSS:
- latestAdd(post, thread_length, postid, parent_post)
- # call discord hook
- if Settings.ENABLE_DISCORD_HOOK and not post["parentid"]:
- hook_url = make_url(postid, post, parent_post or post, True, False)
- discord_hook(post, hook_url)
-
- return (post_url, ttaken, postid)
-
- def delete_post(self, boarddir, postid, imageonly, password, mobile=False):
- OpenDb()
-
- # set the board
- board = setBoard(boarddir)
-
- if board["dir"] == '0':
- 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."
-
- # make sure we have a password
- if not password:
- raise UserError, _("Please enter a password.")
-
- to_delete = []
- if isinstance(postid, list):
- to_delete = [n.value for n in postid]
- else:
- to_delete = [postid]
-
- # delete posts
- 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'
- 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':
- op = get_parent_post(post['parentid'], board['id'])
- if op['last'] != post['timestamp']:
- deltype = '1'
-
- deletePost(to_delete[0], password, deltype, imageonly)
- latestRemove(post['id'])
- regenerateHome()
- else:
- # delete all checked posts (IB)
- deleted = 0
- errors = 0
- msgs = []
-
- for pid in to_delete:
+ link = "/%s/res/%d.html#%d" % (board["dir"], int(
+ post["parentid"]) or int(post["id"]), int(post["id"]))
+
+ # insert report
+ t = time.time()
+ message = cgi.escape(self.formdata["reason"]).strip()[0:8000]
+ message = message.replace("\n", "<br />")
+
+ UpdateDb("INSERT INTO `reports` (board, postid, parentid, link, ip, reason, reporterip, timestamp, timestamp_formatted) VALUES ('%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s')" % (
+ board["dir"], post['id'], post['parentid'], link, post['ip'], _mysql.escape_string(message), _mysql.escape_string(self.environ["REMOTE_ADDR"]), str(t), formatTimestamp(t)))
+ self.output = renderTemplate("report.html", {'finished': True})
+
+ def stats(self):
+ import json
+ import math
+ import platform
try:
- deletePost(pid, password, board['recyclebin'], imageonly)
- latestRemove(pid)
- deleted += 1
- msgs.append('No.%s: Eliminado' % pid)
- except UserError, message:
- errors += 1
- msgs.append('No.%s: %s' % (pid, message))
-
- # regenerate home
- if deleted:
- regenerateHome()
-
- # show errors, if any
- if errors:
- raise UserError, 'No todos los mensajes pudieron ser eliminados.<br />' + '<br />'.join(msgs)
-
- # redirect
- if imageonly:
- self.output += '<html xmlns="http://www.w3.org/1999/xhtml"><body><meta http-equiv="refresh" content="0;url=%s/" /><p>%s</p></body></html>' % (("/cgi/mobile/" if mobile else Settings.BOARDS_URL) + board["dir"], _("File deleted successfully."))
- else:
- self.output += '<html xmlns="http://www.w3.org/1999/xhtml"><body><meta http-equiv="refresh" content="0;url=%s/" /><p>%s</p></body></html>' % (("/cgi/mobile/" if mobile else Settings.BOARDS_URL) + board["dir"], _("Post deleted successfully."))
-
- 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.')
-
- # if there's not a reason, show the report page
- if reason is None:
- self.output += renderTemplate("report.html", {'finished': False, 'postshow': postshow, 'txt': txt})
- return
-
- # check reason
- if not reason:
- raise UserError, _("Enter a reason.")
- if len(reason) > 100:
- raise UserError, _("Text too long.")
-
- # open database
- OpenDb()
-
- # set the board we're in
- board = setBoard(boarddir)
-
- # check if he's banned
- if 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.")
-
- # generate link
- 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)
- else:
- link = "/%s/res/%d.html#%d" % (board["dir"], int(post["parentid"]) or int(post["id"]), int(post["id"]))
-
- # insert report
- t = time.time()
- message = cgi.escape(self.formdata["reason"]).strip()[0:8000]
- message = message.replace("\n", "<br />")
-
- UpdateDb("INSERT INTO `reports` (board, postid, parentid, link, ip, reason, reporterip, timestamp, timestamp_formatted) VALUES ('%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s')" % (board["dir"], post['id'], post['parentid'], link, post['ip'], _mysql.escape_string(message), _mysql.escape_string(self.environ["REMOTE_ADDR"]), str(t), formatTimestamp(t)))
- self.output = renderTemplate("report.html", {'finished': True})
-
- def stats(self):
- import json, math, platform
- try:
- with open('stats.json', 'r') as f:
- out = json.load(f)
- except ValueError:
- out = {'t': 0}
-
- regenerated = False
- if (time.time() - out['t']) > 3600:
- regenerated = True
-
- # open database
- 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)) "
- "FROM posts "
- "WHERE (timestamp-10800) > (UNIX_TIMESTAMP()-604800) AND (IS_DELETED = 0 OR IS_DELETED = 3) "
- "GROUP BY FLOOR((timestamp-10800)/86400) "
- "ORDER BY FLOOR((timestamp-10800)/86400)", 0)
-
- 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]
-
- archive_count = FetchOne("SELECT SUM(length) FROM archive", 0)
- total_archived = int(archive_count[0])
-
- days = []
- for date, count, threads in query_day[1:]:
- days.append( (date, count, threads) )
-
- query_b = FetchAll("SELECT id, dir, name FROM boards WHERE boards.secret = 0", 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])
-
- boards = sorted(boards, key=lambda boards: boards[2], reverse=True)
-
- boards_percent = []
- for dir, longname, bposts in boards:
- if bposts > 0:
- boards_percent.append( (dir, longname, '{0:.2f}'.format( float(bposts)*100/totalp ), int(bposts) ) )
- else:
- boards_percent.append( (dir, longname, '0.00', '0' ) )
-
- #posts = FetchAll("SELECT `parentid`, `boardid` FROM `posts` INNER JOIN `boards` ON posts.boardid = boards.id WHERE posts.parentid<>0 AND posts.timestamp>(UNIX_TIMESTAMP()-86400) AND boards.secret=0 ORDER BY `parentid`")
- #threads = {}
- #for post in posts:
- # if post["parentid"] in threads:
- # threads[post["parentid"]] += 1
- # else:
- # threads[post["parentid"]] = 1
-
- python_version = platform.python_version()
- if self.environ.get('FCGI_FORCE_CGI', 'N').upper().startswith('Y'):
- python_version += " (CGI)"
- else:
- python_version += " (FastCGI)"
-
- out = {
- "uname": platform.uname(),
- "python_ver": python_version,
- "python_impl": platform.python_implementation(),
- "python_build": platform.python_build()[1],
- "python_compiler": platform.python_compiler(),
- "mysql_ver": mysql_ver,
- "tenjin_ver": tenjin.__version__,
- "weabot_ver": __version__,
- "days": days,
- "boards": boards,
- "boards_percent": boards_percent,
- "total": total,
- "total_files": total_files,
- "total_archived": total_archived,
- "t": timestamp(),
- "tz": Settings.TIME_ZONE,
- }
- with open('stats.json', 'w') as f:
- json.dump(out, f)
-
- out['timestamp'] = re.sub(r"\(...\)", " ", formatTimestamp(out['t']))
- out['regenerated'] = regenerated
- self.output = renderTemplate("stats.html", out)
- #self.headers = [("Content-Type", "application/json")]
+ with open('stats.json', 'r') as f:
+ out = json.load(f)
+ except ValueError:
+ out = {'t': 0}
+
+ regenerated = False
+ if (time.time() - out['t']) > 3600:
+ regenerated = True
+
+ # open database
+ 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)) "
+ "FROM posts "
+ "WHERE (timestamp-10800) > (UNIX_TIMESTAMP()-604800) AND (IS_DELETED = 0 OR IS_DELETED = 3) "
+ "GROUP BY FLOOR((timestamp-10800)/86400) "
+ "ORDER BY FLOOR((timestamp-10800)/86400)", 0)
+
+ 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]
+
+ archive_count = FetchOne("SELECT SUM(length) FROM archive", 0)
+ total_archived = int(archive_count[0])
+
+ days = []
+ for date, count, threads in query_day[1:]:
+ days.append((date, count, threads))
+
+ query_b = FetchAll(
+ "SELECT id, dir, name FROM boards WHERE boards.secret = 0", 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])
+
+ boards = sorted(boards, key=lambda boards: boards[2], reverse=True)
+
+ boards_percent = []
+ for dir, longname, bposts in boards:
+ if bposts > 0:
+ boards_percent.append((dir, longname, '{0:.2f}'.format(
+ float(bposts)*100/totalp), int(bposts)))
+ else:
+ boards_percent.append((dir, longname, '0.00', '0'))
+
+ #posts = FetchAll("SELECT `parentid`, `boardid` FROM `posts` INNER JOIN `boards` ON posts.boardid = boards.id WHERE posts.parentid<>0 AND posts.timestamp>(UNIX_TIMESTAMP()-86400) AND boards.secret=0 ORDER BY `parentid`")
+ #threads = {}
+ # for post in posts:
+ # if post["parentid"] in threads:
+ # threads[post["parentid"]] += 1
+ # else:
+ # threads[post["parentid"]] = 1
+
+ python_version = platform.python_version()
+ if self.environ.get('FCGI_FORCE_CGI', 'N').upper().startswith('Y'):
+ python_version += " (CGI)"
+ else:
+ python_version += " (FastCGI)"
+
+ out = {
+ "uname": platform.uname(),
+ "python_ver": python_version,
+ "python_impl": platform.python_implementation(),
+ "python_build": platform.python_build()[1],
+ "python_compiler": platform.python_compiler(),
+ "mysql_ver": mysql_ver,
+ "tenjin_ver": tenjin.__version__,
+ "weabot_ver": __version__,
+ "days": days,
+ "boards": boards,
+ "boards_percent": boards_percent,
+ "total": total,
+ "total_files": total_files,
+ "total_archived": total_archived,
+ "t": timestamp(),
+ "tz": Settings.TIME_ZONE,
+ }
+ with open('stats.json', 'w') as f:
+ json.dump(out, f)
+
+ out['timestamp'] = re.sub(r"\(...\)", " ", formatTimestamp(out['t']))
+ out['regenerated'] = regenerated
+ self.output = renderTemplate("stats.html", out)
+ #self.headers = [("Content-Type", "application/json")]
+
if __name__ == "__main__":
- from fcgi import WSGIServer
-
- # Psyco is not required, however it will be used if available
- try:
- import psyco
- logTime("Psyco se ha instalado")
- psyco.bind(tenjin.helpers.to_str)
- psyco.bind(weabot.run, 2)
- psyco.bind(getFormData)
- psyco.bind(setCookie)
- psyco.bind(threadUpdated)
- psyco.bind(processImage)
- except:
- pass
-
- WSGIServer(weabot).run()
+ from fcgi import WSGIServer
+
+ # Psyco is not required, however it will be used if available
+ try:
+ import psyco
+ logTime("Psyco se ha instalado")
+ psyco.bind(tenjin.helpers.to_str)
+ psyco.bind(weabot.run, 2)
+ psyco.bind(getFormData)
+ psyco.bind(setCookie)
+ psyco.bind(threadUpdated)
+ psyco.bind(processImage)
+ except:
+ pass
+ WSGIServer(weabot).run()