# coding=utf-8
import os
import cgi
import html
import shutil
import datetime
import logging
from database import *
from settings import Settings
from framework import *
from formatting import *
from template import *
from post import *
def manage(self, path_split):
page = ''
validated = False
administrator = False
moderator = True
skiptemplate = False
staff_account = None
if 'username' in self.formdata and 'password' in self.formdata:
# If no admin accounts available, create admin:admin
first_admin = FetchOne("SELECT 1 FROM `staff` WHERE `rights` = 0 LIMIT 1")
if not first_admin:
InsertDb("INSERT INTO `staff` (`username`, `password`, `added`, `rights`) VALUES ('admin', %s, 0, 0)", (genPasswdHash("admin"),))
staff_account = verifyPasswd(self.formdata['username'], self.formdata['password'])
if staff_account:
session_uuid = newSession(staff_account['id'])
setCookie(self, 'weabot_manage', session_uuid)
UpdateDb("DELETE FROM `logs` WHERE `timestamp` < %s", (timestamp() - Settings.MANAGE_LOG_TIME,))
else:
page += _('Incorrect username/password.')
logAction('', 'Failed login. U:'+self.formdata['username']+' IP logged.')
logging.warn("Failed login. U:{} IP:{}".format(self.formdata['username'], self.ip))
else:
# Validate existing session
manage_cookie = getCookie(self, 'weabot_manage')
if manage_cookie:
staff_account = validateSession(manage_cookie)
if not staff_account:
page += "La sesión ha expirado. Por favor ingresa tus credenciales nuevamente."
deleteCookie(self, 'weabot_manage')
if staff_account:
validated = True
if 'session_id' in staff_account:
renewSession(staff_account['session_id'])
if staff_account['rights'] in [0, 1, 2]:
administrator = True
if staff_account['rights'] == 2:
moderator = False
UpdateDb('UPDATE `staff` SET `lastactive` = %s WHERE `id` = %s LIMIT 1',
(timestamp(), staff_account['id']))
if not validated:
template_filename = "login.html"
template_values = {}
else:
if len(path_split) > 2:
if path_split[2] == 'rebuild':
if not administrator:
return
try:
board_dir = path_split[3]
except:
board_dir = ''
if board_dir == '':
template_filename = "rebuild.html"
template_values = {'boards': boardlist()}
else:
everything = ("everything" in self.formdata)
if board_dir == '!ALL':
t1 = time.time()
boards = FetchAll(
'SELECT `dir` FROM `boards` WHERE secret = 0')
for board in boards:
board = setBoard(board['dir'])
regenerateBoard(everything)
message = _('Rebuilt %(board)s in %(time)s seconds.') % {
'board': _('all boards'), 'time': timeTaken(t1, time.time())}
logAction(staff_account['username'], _(
'Rebuilt %s') % _('all boards'))
elif board_dir == '!BBS':
t1 = time.time()
boards = FetchAll(
'SELECT `dir` FROM `boards` WHERE `board_type` = 1')
for board in boards:
board = setBoard(board['dir'])
regenerateBoard(everything)
message = _('Rebuilt %(board)s in %(time)s seconds.') % {
'board': _('all boards'), 'time': timeTaken(t1, time.time())}
logAction(staff_account['username'], _(
'Rebuilt %s') % _('all boards'))
elif board_dir == '!IB':
t1 = time.time()
boards = FetchAll(
'SELECT `dir` FROM `boards` WHERE `board_type` = 1')
for board in boards:
board = setBoard(board['dir'])
regenerateBoard(everything)
message = _('Rebuilt %(board)s in %(time)s seconds.') % {
'board': _('all boards'), 'time': timeTaken(t1, time.time())}
logAction(staff_account['username'], _(
'Rebuilt %s') % _('all boards'))
elif board_dir == '!HOME':
t1 = time.time()
regenerateHome()
message = _('Rebuilt %(board)s in %(time)s seconds.') % {
'board': _('home'), 'time': timeTaken(t1, time.time())}
logAction(staff_account['username'], _(
'Rebuilt %s') % _('home'))
elif board_dir == '!NEWS':
t1 = time.time()
regenerateNews()
message = _('Rebuilt %(board)s in %(time)s seconds.') % {
'board': _('news'), 'time': timeTaken(t1, time.time())}
logAction(staff_account['username'], _(
'Rebuilt %s') % _('news'))
elif board_dir == '!TRASH':
t1 = time.time()
regenerateTrash()
message = _('Rebuilt %(board)s in %(time)s seconds.') % {
'board': _('trash'), 'time': timeTaken(t1, time.time())}
logAction(staff_account['username'], _(
'Rebuilt %s') % _('trash'))
elif board_dir == '!KAKO':
t1 = time.time()
boards = FetchAll(
'SELECT `dir` FROM `boards` WHERE archive = 1')
for board in boards:
board = setBoard(board['dir'])
regenerateKako()
message = _('Rebuilt %(board)s in %(time)s seconds.') % {
'board': 'kako', 'time': timeTaken(t1, time.time())}
logAction(staff_account['username'], _(
'Rebuilt %s') % 'kako')
elif board_dir == '!HTACCESS':
t1 = time.time()
if regenerateAccess():
message = _('Rebuilt %(board)s in %(time)s seconds.') % {
'board': _('htaccess'), 'time': timeTaken(t1, time.time())}
logAction(staff_account['username'], _(
'Rebuilt %s') % _('htaccess'))
else:
message = _(
'htaccess regeneration deactivated by sysop.')
else:
t1 = time.time()
board = setBoard(board_dir)
regenerateBoard(everything)
message = _('Rebuilt %(board)s in %(time)s seconds.') % {
'board': '/' + board['dir'] + '/', 'time': timeTaken(t1, time.time())}
logAction(staff_account['username'],
'Rebuilt /' + board['dir'] + '/')
template_filename = "message.html"
elif path_split[2] == 'mod':
if not moderator:
return
try:
board = setBoard(path_split[3])
except:
board = ""
if not board:
template_filename = "mod.html"
template_values = {"mode": 1, 'boards': boardlist()}
elif len(path_split) > 4:
parentid = int(path_split[4])
# make sure it's the full thread
check = FetchOne("SELECT `parentid` FROM `posts` WHERE `id` = %s AND `boardid` = %s LIMIT 1", (parentid, board['id']))
if check['parentid']:
parentid = int(check['parentid'])
posts = FetchAll('SELECT id, timestamp, timestamp_formatted, name, message, file, thumb, IS_DELETED, locked, subject, length, INET6_NTOA(ip) AS ip FROM `posts` WHERE (parentid = %s OR id = %s) AND boardid = %s ORDER BY `id` ASC', (parentid, parentid, board['id']))
template_filename = "mod.html"
template_values = {"mode": 3, "dir": board["dir"], "posts": posts}
else:
threads = FetchAll("SELECT * FROM `posts` WHERE boardid = %s AND parentid = 0 ORDER BY `bumped` DESC" % board["id"])
template_filename = "mod.html"
template_values = {"mode": 2, "dir": board["dir"], "threads": threads}
elif path_split[2] == 'recent':
posts = FetchAll("SELECT posts.id, posts.subject, dir, boards.board_type, CASE parentid WHEN '0' THEN posts.id ELSE parentid END AS parentid, file, thumb, timestamp_formatted, timestamp, posts.message, INET6_NTOA(ip) AS ip, posts.name, email, tripcode, posts.IS_DELETED, boards.name AS board_name FROM posts INNER JOIN boards ON posts.boardid = boards.id WHERE posts.timestamp > UNIX_TIMESTAMP() - 86400 ORDER BY timestamp DESC")
template_filename = "recent.html"
template_values = {"posts": posts}
elif path_split[2] == 'staff':
if staff_account['rights'] != 0:
return
action_taken = False
if len(path_split) > 3:
if path_split[3] == 'add' or path_split[3] == 'edit':
member = None
member_username = ''
member_rights = 3
if path_split[3] == 'edit':
if len(path_split) > 4:
member = FetchOne('SELECT * FROM `staff` WHERE `id` = %s LIMIT 1', (path_split[4],))
if member:
member_username = member['username']
member_rights = member['rights']
action = 'edit/' + str(member['id'])
try:
if self.formdata.get('user'):
if self.formdata['rights'] in [0, 1, 2, 3]:
action_taken = True
UpdateDb("UPDATE `staff` SET `username` = %s, `rights` = %s WHERE `id` = LIMIT 1",
(self.formdata['user'], self.formdata['rights'], member['id']))
message = _(
'Staff member updated.')
logAction(staff_account['username'], _(
'Updated staff account for %s') % self.formdata['user'])
template_filename = "message.html"
except:
pass
else:
action = 'add'
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
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:
action_taken = True
message = _(
'That username is already in use.')
template_filename = "message.html"
if not action_taken:
action_taken = True
if action == 'add':
submit = 'Agregar'
else:
submit = 'Editar'
template_filename = "staff.html"
template_values = {'mode': 1,
'action': action,
'member': member,
'member_username': member_username,
'member_rights': member_rights,
'submit': submit}
elif path_split[3] == 'delete':
if not moderator:
return
action_taken = True
message = '' + _('Click here to confirm the deletion of that staff member') + ''
template_filename = "message.html"
elif path_split[3] == 'delete_confirmed':
if not moderator:
return
action_taken = True
member = FetchOne('SELECT `username` FROM `staff` WHERE `id` = %s LIMIT 1', (path_split[4],))
if member:
UpdateDb('DELETE FROM `staff` WHERE `id` = %s LIMIT 1', (path_split[4],))
message = 'Staff member deleted.'
template_filename = "message.html"
logAction(staff_account['username'], _(
'Deleted staff account for %s') % member['username'])
else:
message = _(
'Unable to locate a staff account with that ID.')
template_filename = "message.html"
if not action_taken:
staff = FetchAll('SELECT * FROM `staff` ORDER BY `rights`')
for member in staff:
if member['rights'] == 0:
member['rights'] = _('Super-administrator')
elif member['rights'] == 1:
member['rights'] = _('Administrator')
elif member['rights'] == 2:
member['rights'] = _('Developer')
elif member['rights'] == 3:
member['rights'] = _('Moderator')
if member['lastactive']:
member['lastactivestamp'] = member['lastactive']
member['lastactive'] = formatTimestamp(
member['lastactive'])
else:
member['lastactive'] = _('Never')
member['lastactivestamp'] = 0
template_filename = "staff.html"
template_values = {'mode': 0, 'staff': staff}
elif path_split[2] == 'delete':
if not moderator:
return
do_ban = False
try:
if self.formdata['ban'] == 'true':
do_ban = True
except:
pass
board = setBoard(path_split[3])
post = FetchOne('SELECT id, message, thumb, name, tripcode FROM posts WHERE boardid = %s AND id = %s LIMIT 1' % (board['id'], path_split[4]))
template_filename = "delete.html"
template_values = {'do_ban': do_ban,
'curboard': board,
'post': post }
elif path_split[2] == 'delete_confirmed':
if not moderator:
return
do_ban = self.formdata.get('ban')
permanently = self.formdata.get('perma')
imageonly = self.formdata.get('imageonly')
board = setBoard(path_split[3])
postid = int(path_split[4])
post = FetchOne('SELECT id, message, parentid, INET6_NTOA(ip) AS ip FROM posts WHERE boardid = %s AND id = %s' % (board['id'], postid))
if not permanently:
deletePost(path_split[4], None, 2, imageonly)
regenerateTrash()
else:
deletePost(path_split[4], None, 0, imageonly)
regenerateHome()
# Borrar denuncias
UpdateDb("DELETE FROM `reports` WHERE `postid` = %s",
(int(path_split[4]),))
boards = FetchAll('SELECT `name`, `dir` FROM `boards` ORDER BY `dir`')
if imageonly:
message = 'Archivo de post /%s/%s eliminado.' % (
board['dir'], post['id'])
elif permanently or post["parentid"] == 0:
message = 'Post /%s/%s eliminado permanentemente.' % (
board['dir'], post['id'])
else:
message = 'Post /%s/%s enviado a la papelera.' % (
board['dir'], post['id'])
template_filename = "message.html"
logAction(staff_account['username'], message +
' Contenido: ' + post['message'] + ' IP: ' + post['ip'])
if do_ban:
message = _('Redirecting to ban page...') + ''
template_filename = "message.html"
elif path_split[2] == 'lock':
setLocked = 0
# Nos vamos al board y ubicamos el post
board = setBoard(path_split[3])
pid = int(path_split[4])
post = FetchOne('SELECT id, parentid, locked FROM posts WHERE boardid = %s AND id = %s LIMIT 1', (board['id'], pid) )
if not post:
message = _('Unable to locate a post with that ID.')
template_filename = "message.html"
else:
if post['parentid'] != 0:
message = _('Post is not a thread opener.')
template_filename = "message.html"
else:
if post['locked'] == 0:
# Cerrar si esta abierto
setLocked = 1
else:
# Abrir si esta cerrado
setLocked = 0
UpdateDb("UPDATE `posts` SET `locked` = %s WHERE `boardid` = %s AND `id` = %s LIMIT 1",
(setLocked, board["id"], post["id"]))
threadUpdated(pid)
if setLocked == 1:
message = _('Thread successfully closed.')
logAction(staff_account['username'], _('Closed thread %s') % ('/' + board['dir'] + '/' + str(pid)) )
else:
message = _('Thread successfully opened.')
logAction(staff_account['username'], _('Opened thread %s') % ('/' + board['dir'] + '/' + str(pid)) )
template_filename = "message.html"
elif path_split[2] == 'permasage':
setPermasaged = 0
# Nos vamos al board y ubicamos el post
board = setBoard(path_split[3])
pid = int(path_split[4])
post = FetchOne('SELECT `parentid`, `locked` FROM `posts` WHERE `boardid` = %s AND `id` = %s LIMIT 1', (board['id'], pid) )
if not post:
message = 'No se encuentra un hilo con ese ID.'
template_filename = "message.html"
elif post['locked'] == 1:
message = 'Solo se puede aplicar permasage en un hilo abierto.'
template_filename = "message.html"
else:
if post['parentid']:
message = 'El post indicado es una respuesta a un hilo.'
template_filename = "message.html"
else:
if post['locked'] == 2:
# Sacar permasage
setPermasaged = 0
else:
# Colocar permasage
setPermasaged = 2
UpdateDb("UPDATE `posts` SET `locked` = %s WHERE `boardid` = '%s' AND `id` = '%s' LIMIT 1" % (setPermasaged, board["id"], pid) )
regenerateFrontPages()
threadUpdated(pid)
if setPermasaged == 2:
message = 'Thread successfully permasaged.'
logAction(staff_account['username'], 'Activado permasage en el hilo /%s/%s' % (board['dir'], pid) )
else:
message = 'Thread successfully un-permasaged.'
logAction(staff_account['username'], 'Desactivado permasage en el hilo /%s/%s' % (board['dir'], pid) )
template_filename = "message.html"
elif path_split[2] == 'move':
raise NotImplementedError
#if not moderator:
if not administrator:
return
oldboardid = ""
oldthread = ""
newboardid = ""
try:
oldboardid = path_split[3]
oldthread = path_split[4]
newboardid = path_split[5]
except:
pass
try:
oldboardid = self.formdata['oldboardid']
oldthread = self.formdata['oldthread']
newboardid = self.formdata['newboardid']
except:
pass
if oldboardid and oldthread and newboardid:
message = "import"
import shutil
message += "ok"
board = setBoard(oldboardid)
oldboard = board['dir']
oldboardsubject = board['subject']
oldboardname = random.choice(board["anonymous"].split('|'))
# get old posts
posts = FetchAll(
"SELECT * FROM `posts` WHERE (`id` = {0} OR `parentid` = {0}) AND `boardid` = {1} ORDER BY id ASC".format(oldthread, board['id']))
# switch to new board
board = setBoard(newboardid)
newboard = board['dir']
refs = {}
moved_files = []
moved_thumbs = []
moved_cats = []
newthreadid = 0
newthread = 0
num = 1
message = "from total: %s
" % len(posts)
template_filename = "message.html"
for p in posts:
# save old post ID
old_id = p['id']
is_op = bool(p['parentid'] == '0')
# copy post object but without ID and target boardid
post = Post()
post.post = p
post.post.pop("id")
post["boardid"] = board['id']
post["parentid"] = newthreadid
# save the files we need to move if any
if post['IS_DELETED'] == '0':
if post['file']:
moved_files.append(post['file'])
if post['thumb']:
moved_thumbs.append(post['thumb'])
if is_op:
moved_cats.append(post['thumb'])
# fix subject if necessary
if post['subject'] and post['subject'] == oldboardsubject:
post['subject'] = board['subject']
# fix new default name
if post['name'] == oldboardname:
post['name'] = board['anonymous']
# fix date
post['timestamp_formatted'] = formatTimestamp(post['timestamp'])
#(re)add post ID if necessary
if board["useid"] != '0':
if post["parentid"]:
tym = parent_time
else:
tym = post["timestamp"]
post['posterid'] = iphash(post['ip'], post, tym, board["useid"], False, '', False, False, (board["countrycode"] in [1, 2]))
# insert new post and get its new ID
new_id = post.insert()
# save the reference (BBS = post number, IB = new ID)
refs[old_id] = num if board['board_type'] == 1 else new_id
# this was an OP
message += "newthread = %s parentid = %s
" % (
newthreadid, p['parentid'])
if is_op:
oldthread = old_id
newthreadid = new_id
oldbumped = post["bumped"]
# BBS = new thread timestamp, IB = new thread ID
newthread = post['timestamp'] if board['board_type'] == 1 else new_id
parent_time = post['timestamp']
# log it
message += "%s -> %s
" % (old_id, new_id)
num += 1
# fix anchors
for old, new in refs.items():
old_url = "/{oldboard}/res/{oldthread}.html#{oldpost}\">>>{oldpost}".format(
oldboard=oldboard, oldthread=oldthread, oldpost=old)
if board['board_type'] == 1:
new_url = "/{newboard}/read/{newthread}/{newpost}\">>>{newpost}".format(
newboard=newboard, newthread=newthread, newpost=new)
else:
new_url = "/{newboard}/res/{newthread}.html#{newpost}\">>>{newpost}".format(
newboard=newboard, newthread=newthread, newpost=new)
sql = "UPDATE `posts` SET `message` = REPLACE(message, '{old}', '{new}') WHERE `boardid` = {newboardid} AND (`id` = {newthreadid} OR `parentid` = {newthreadid})".format(
old=old_url, new=new_url, newboardid=board['id'], newthreadid=newthreadid)
message += sql + "
"
UpdateDb(sql)
# copy files
for file in moved_files:
if not os.path.isfile(Settings.IMAGES_DIR + newboard + "/src/" + file):
shutil.copyfile(Settings.IMAGES_DIR + oldboard + "/src/" +
file, Settings.IMAGES_DIR + newboard + "/src/" + file)
for thumb in moved_thumbs:
if not os.path.isfile(Settings.IMAGES_DIR + newboard + "/thumb/" + thumb):
shutil.copyfile(Settings.IMAGES_DIR + oldboard + "/thumb/" +
thumb, Settings.IMAGES_DIR + newboard + "/thumb/" + thumb)
if not os.path.isfile(Settings.IMAGES_DIR + newboard + "/mobile/" + thumb):
shutil.copyfile(Settings.IMAGES_DIR + oldboard + "/mobile/" +
thumb, Settings.IMAGES_DIR + newboard + "/mobile/" + thumb)
for cat in moved_cats:
try:
if not os.path.isfile(Settings.IMAGES_DIR + newboard + "/cat/" + thumb):
shutil.copyfile(Settings.IMAGES_DIR + oldboard + "/cat/" +
thumb, Settings.IMAGES_DIR + newboard + "/cat/" + thumb)
except:
pass
# lock original, set expiration to 1 day
exp = timestamp()+86400
exp_format = datetime.datetime.fromtimestamp(exp).strftime("%d/%m")
sql = "UPDATE `posts` SET `locked`=1, `expires`={exp}, `expires_formatted`=\"{exp_format}\" WHERE `boardid`=\"{oldboard}\" AND id=\"{oldthread}\"".format(exp=exp, exp_format=exp_format, oldboard=oldboardid, oldthread=oldthread)
UpdateDb(sql)
# insert notice message
if 'msg' in self.formdata:
leavemsg = True
board = setBoard(oldboard)
if board['board_type'] == 1:
thread_url = "/{newboard}/read/{newthread}".format(newboard=newboard, newthread=newthread)
else:
thread_url = "/{newboard}/res/{newthread}.html".format(newboard=newboard, newthread=newthread)
notice_post = Post(board["id"])
notice_post["parentid"] = oldthread
if board['board_type'] == "0":
notice_post["subject"] = "Aviso"
notice_post["name"] = "Sistema"
notice_post["message"] = "El hilo ha sido movido a /{newboard}/{newthread}.".format(
url=thread_url, newboard=newboard, newthread=newthread)
notice_post["timestamp"] = timestamp()+1
notice_post["timestamp_formatted"] = "Hilo movido"
notice_post["bumped"] = oldbumped
notice_post.insert()
regenerateFrontPages()
regenerateThreadPage(oldthread)
# regenerate again (fix?)
board = setBoard(newboardid)
regenerateFrontPages()
regenerateThreadPage(newthreadid)
message += "done"
logAction(staff_account['username'], "Movido hilo %s/%s a %s/%s." % (oldboard, oldthread, newboard, newthread))
else:
template_filename = "move.html"
template_values = {'boards': boardlist(
), 'oldboardid': oldboardid, 'oldthread': oldthread}
elif path_split[2] == 'ban':
if not moderator:
return
if len(path_split) > 4:
board = setBoard(path_split[3])
post = FetchOne('SELECT INET6_NTOA(`ip`) AS `ip` FROM `posts` WHERE `boardid` = %s AND `id` = %s LIMIT 1' % (board['id'], int(path_split[4])) )
if not post:
message = _('Unable to locate a post with that ID.')
template_filename = "message.html"
else:
message = 'Espere...'
template_filename = "message.html"
else:
reason = self.formdata.get('reason')
if reason is not None:
# Start ban process
import netaddr
ip = self.formdata['ip']
# Parse CIDR or IP glob
try:
if netaddr.valid_ipv4(ip) or netaddr.valid_ipv6(ip):
ipaddress = netaddr.IPAddress(ip)
ipstart = ipend = ipstr = str(ipaddress)
elif netaddr.valid_glob(ip):
iprange = netaddr.glob_to_iprange(ip)
ipstart, ipend = str(iprange[0]), str(iprange[-1])
cidrs = iprange.cidrs()
if len(cidrs) == 1:
ipstr = str(cidrs[0])
else:
ipstr = str(iprange)
elif '/' in ip:
# Try with CIDR
ipnetwork = netaddr.IPNetwork(ip)
ipstart, ipend = str(ipnetwork[0]), str(ipnetwork[-1])
ipstr = str(ipnetwork)
else:
self.error("IP o rango inválido.")
return
except netaddr.core.AddrFormatError as e:
self.error("Problema con el IP o rango ingresado: {}".format(e))
return
if self.formdata['seconds'] != '0':
until = timestamp() + int(self.formdata['seconds'])
else:
until = 0
where = ''
if 'board_all' not in self.formdata:
where = []
boards = FetchAll('SELECT `dir` FROM `boards`')
for board in boards:
keyname = 'board_' + board['dir']
if keyname in self.formdata:
if self.formdata[keyname] == "1":
where.append(board['dir'])
if len(where) > 0:
where = boards2str(where)
else:
self.error(
_("You must select where the ban shall be placed"))
return
if 'edit' in self.formdata:
UpdateDb("DELETE FROM `bans` WHERE `id` = '" + _mysql.escape_string(self.formdata['edit']) + "' LIMIT 1")
"""else: # TODO : Duplicate check
ban = FetchOne("SELECT `id` FROM `bans` WHERE `ip` = '" + _mysql.escape_string(
ip) + "' AND `boards` = '" + _mysql.escape_string(where) + "' LIMIT 1")
if ban:
self.error(_('There is already an identical ban for this IP.') + '' + _('Edit') + '')
return"""
# Blind mode
blind = self.formdata.get('blind', 0)
#raise UserError, "{} {} {}".format(ipstart, ipend, ipstr)
# Banear sin mensaje
InsertDb("INSERT INTO `bans` (`ipstart`, `ipend`, `ipstr`, `boards`, `added`, `until`, `staff`, `reason`, `note`, `blind`) VALUES "
"(INET6_ATON(%s), INET6_ATON(%s), %s, %s, %s, %s, %s, %s, %s, %s)",
(ipstart, ipend, ipstr, where, timestamp(), until, staff_account['username'], self.formdata['reason'], self.formdata['note'], blind))
regenerateAccess()
if 'edit' in self.formdata:
message = _('Ban successfully edited.')
action = 'Edited ban for ' + ip
else:
message = _('Ban successfully placed.')
action = 'Banned ' + ip
if until != 0:
action += ' until ' + \
formatTimestamp(until)
else:
action += ' permanently'
logAction(staff_account['username'], action)
template_filename = 'message.html'
else:
startvalues = {'where': [],
'reason': '',
'note': '',
'message': '(GET OUT)',
'seconds': 0,
'blind': 1}
edit_id = 0
if 'edit' in self.formdata:
edit_id = self.formdata['edit']
ban = FetchOne("SELECT `id`, INET6_NTOA(`ip`) AS 'ip', CASE WHEN `netmask` IS NULL THEN '255.255.255.255' ELSE INET_NTOA(`netmask`) END AS 'netmask', boards, added, until, staff, reason, note, blind FROM `bans` WHERE `id` = %s ORDER BY `added` DESC", (edit_id) )
if ban:
if ban['boards'] == '':
where = ''
else:
where = boards2str(ban['boards'])
if ban['until'] == '0':
until = 0
else:
until = int(ban['until']) - timestamp()
startvalues = {'where': where,
'reason': ban['reason'],
'note': ban['note'],
'seconds': str(until),
'blind': ban['blind']
}
else:
edit_id = 0
template_filename = "bans.html"
template_values = {'mode': 1,
'boards': boardlist(),
'ip': self.formdata.get('ip'),
'startvalues': startvalues,
'edit_id': edit_id}
elif path_split[2] == 'bans':
if not moderator:
return
action_taken = False
if len(path_split) > 4:
if path_split[3] == 'delete':
ip = FetchOne("SELECT ipstr FROM `bans` WHERE `id` = %s LIMIT 1",
(path_split[4],))
if ip:
# Delete ban
UpdateDb('DELETE FROM `bans` WHERE `id` = %s LIMIT 1',
(path_split[4],))
regenerateAccess()
message = _('Ban successfully deleted.')
template_filename = "message.html"
logAction(staff_account['username'], _(
'Deleted ban for %s') % ip)
else:
message = _(
'There was a problem while deleting that ban. It may have already been removed, or recently expired.')
template_filename = "message.html"
if not action_taken:
bans = FetchAll(
"SELECT `id`, `ipstr` AS 'ip', boards, added, until, staff, reason, note, blind FROM `bans` ORDER BY `added` DESC")
if bans:
for ban in bans:
if ban['boards'] == '':
ban['boards'] = _('All boards')
else:
where = str2boards(ban['boards'])
if len(where) > 1:
ban['boards'] = '/' + \
'/, /'.join(where) + '/'
else:
ban['boards'] = '/' + where[0] + '/'
ban['added'] = formatTimestamp(ban['added'])
if ban['until'] == 0:
ban['until'] = _('Does not expire')
else:
ban['until'] = formatTimestamp(ban['until'])
if ban['blind']:
ban['blind'] = 'Sí'
else:
ban['blind'] = 'No'
template_filename = "bans.html"
template_values = {'mode': 0, 'bans': bans}
elif path_split[2] == 'changepassword':
form_submitted = False
try:
if self.formdata['oldpassword'] != '' and self.formdata['newpassword'] != '' and self.formdata['newpassword2'] != '':
form_submitted = True
except:
pass
if form_submitted:
if verifyPasswd(staff_account['username'], self.formdata['oldpassword']):
if self.formdata['newpassword'] == self.formdata['newpassword2']:
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"
else:
message = _('Passwords did not match.')
template_filename = "message.html"
else:
message = _('Current password incorrect.')
template_filename = "message.html"
else:
template_filename = "changepassword.html"
template_values = {}
elif path_split[2] == 'board':
if not administrator:
return
if len(path_split) > 3:
board = setBoard(path_split[3])
form_submitted = False
try:
if self.formdata['name'] != '':
form_submitted = True
except:
pass
if form_submitted:
rebuild = 0
RB_FRONT = BIT(0)
RB_ALL = BIT(1)
RB_KAKO = BIT(2)
RB_HOME = BIT(3)
# Update board settings
if self.formdata['longname'] != board['longname']:
board['longname'] = self.formdata['longname']
if board['board_type'] == 1:
rebuild |= RB_FRONT
else:
rebuild |= RB_ALL
if board['name'] != self.formdata['name']:
board['name'] = self.formdata['name']
rebuild |= RB_ALL
if board['board_type'] == 1:
rebuild |= RB_KAKO
if board['subname'] != self.formdata['subname']:
board['subname'] = self.formdata['subname']
rebuild |= RB_HOME
board['anonymous'] = self.formdata['anonymous']
board['subject'] = self.formdata['subject']
board['message'] = self.formdata['message']
board['useid'] = self.formdata['useid']
board['slip'] = self.formdata['slip']
board['countrycode'] = self.formdata['countrycode']
if 'recyclebin' in self.formdata:
board['recyclebin'] = 1
else:
board['recyclebin'] = 0
if 'disable_name' in self.formdata and not board['disable_name']:
board['disable_name'] = 1
if board['board_type'] == 0:
rebuild |= RB_ALL
elif 'disable_name' not in self.formdata and board['disable_name']:
board['disable_name'] = 0
if board['board_type'] == 0:
rebuild |= RB_ALL
if 'disable_subject' in self.formdata and not board['disable_subject']:
board['disable_subject'] = 1
if board['board_type'] == 0:
rebuild |= RB_ALL
elif 'disable_subject' not in self.formdata and board['disable_subject']:
board['disable_subject'] = 0
if board['board_type'] == 0:
rebuild |= RB_ALL
if 'secret' in self.formdata:
board['secret'] = 1
else:
board['secret'] = 0
if 'locked' in self.formdata:
board['locked'] = 1
else:
board['locked'] = 0
if board['postarea_desc'] != self.formdata['postarea_desc']:
board['postarea_desc'] = self.formdata['postarea_desc']
if board['board_type'] == 1:
rebuild |= RB_FRONT
else:
rebuild |= RB_ALL
if board['postarea_extra'] != self.formdata['postarea_extra']:
board['postarea_extra'] = self.formdata['postarea_extra']
if board['board_type'] == 1:
rebuild |= RB_FRONT
else:
rebuild |= RB_ALL
if board['force_css'] != self.formdata['force_css']:
board['force_css'] = self.formdata['force_css']
rebuild |= RB_ALL
if 'allow_noimage' in self.formdata and not board['allow_noimage']:
board['allow_noimage'] = 1
if board['board_type'] == 0:
rebuild |= RB_ALL
elif 'allow_noimage' not in self.formdata and board['allow_noimage']:
board['allow_noimage'] = 0
if board['board_type'] == 0:
rebuild |= RB_ALL
if 'allow_images' in self.formdata and not board['allow_images']:
board['allow_images'] = 1
rebuild |= RB_FRONT
elif 'allow_images' not in self.formdata and board['allow_images']:
board['allow_images'] = 0
rebuild |= RB_FRONT
if 'allow_image_replies' in self.formdata and not board['allow_image_replies']:
board['allow_image_replies'] = 1
rebuild |= RB_ALL
elif 'allow_image_replies' not in self.formdata and board['allow_image_replies']:
board['allow_image_replies'] = 0
rebuild |= RB_ALL
if 'allow_spoilers' in self.formdata and not board['allow_spoilers']:
board['allow_spoilers'] = 1
if board['board_type'] == 0:
rebuild |= RB_ALL
elif 'allow_spoilers' not in self.formdata and board['allow_spoilers']:
board['allow_spoilers'] = 0
if board['board_type'] == 0:
rebuild |= RB_ALL
if 'allow_oekaki' in self.formdata and not board['allow_oekaki']:
board['allow_oekaki'] = 1
if board['board_type'] == 0:
rebuild |= RB_ALL
elif 'allow_oekaki' not in self.formdata and board['allow_oekaki']:
board['allow_oekaki'] = 0
if board['board_type'] == 0:
rebuild |= RB_ALL
if 'archive' in self.formdata:
board['archive'] = 1
else:
board['archive'] = 0
# update file types
new_filetypes = [(ft.replace('filetype', '')) for ft in self.formdata if ft.startswith('filetype')]
if sorted(board['filetypes_ext']) != sorted(new_filetypes):
UpdateDb("DELETE FROM boards_filetypes WHERE boardid = %s", (board['id'],) )
for filetype in filetypelist():
if 'filetype'+filetype['ext'] in self.formdata:
UpdateDb("INSERT INTO boards_filetypes VALUES (%s, %s)", (board['id'], filetype['id']) )
if board['board_type'] == 0:
rebuild |= RB_ALL
try:
if board['numthreads'] != int(self.formdata['numthreads']):
board['numthreads'] = int(self.formdata['numthreads'])
rebuild |= RB_FRONT
except:
raise UserError(_("Max threads shown must be numeric."))
try:
if board['numcont'] != int(self.formdata['numcont']):
board['numcont'] = int(self.formdata['numcont'])
rebuild |= RB_FRONT
except:
raise UserError(_("Max replies shown must be numeric."))
try:
if board['numline'] != int(self.formdata['numline']):
board['numline'] = int(self.formdata['numline'])
rebuild |= RB_FRONT
except:
raise UserError(_("Max lines shown must be numeric."))
try:
if board['thumb_px'] != int(self.formdata['thumb_px']):
board['thumb_px'] = int(self.formdata['thumb_px'])
if board['board_type'] == 0:
rebuild |= RB_ALL
except:
raise UserError(_("Max thumb dimensions must be numeric."))
try:
if board['maxsize'] != int(self.formdata['maxsize']):
board['maxsize'] = int(self.formdata['maxsize'])
if board['board_type'] == 0:
rebuild |= RB_ALL
except:
raise UserError(_("Max size must be numeric."))
try:
if board['maxage'] != int(self.formdata['maxage']):
board['maxage'] = int(self.formdata['maxage'])
if board['board_type'] == 0:
rebuild |= RB_ALL
except:
raise UserError(_("Max age must be numeric."))
try:
if board['maxinactive'] != int(self.formdata['maxinactive']):
board['maxinactive'] = int(self.formdata['maxinactive'])
if board['board_type'] == 0:
rebuild |= RB_ALL
except:
raise UserError(_("Max inactivity must be numeric."))
try:
board['threadsecs'] = int(self.formdata['threadsecs'])
except:
raise UserError(_("Time between new threads must be numeric."))
try:
board['postsecs'] = int(self.formdata['postsecs'])
except:
raise UserError(_("Time between replies must be numeric."))
new_type = int(self.formdata['type'])
if new_type != board['board_type']:
switchBoard(new_type)
board['board_type'] = new_type
rebuild |= RB_ALL
updateBoardSettings()
board = setBoard(board['dir'])
if rebuild & RB_ALL:
regenerateBoard(everything=True)
elif rebuild & RB_FRONT:
regenerateBoard()
if rebuild & RB_KAKO:
regenerateKako()
if rebuild & RB_HOME:
regenerateHome()
message = _('Board options successfully updated.')
template_filename = "message.html"
logAction(staff_account['username'], _('Updated options for /%s/') % board['dir'])
else:
template_filename = "boardoptions.html"
template_values = { 'mode': 1,
'boardopts': board,
'filetypes': filetypelist(),
'supported_filetypes': board['filetypes_ext'] }
else:
# List all boards
template_filename = "boardoptions.html"
template_values = {'mode': 0, 'boards': boardlist()}
elif path_split[2] == 'recyclebin':
if not administrator:
return
message = None
if len(path_split) > 5:
if path_split[4] == 'restore':
board = setBoard(path_split[5])
post = FetchOne('SELECT `parentid`, `IS_DELETED` 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.') + '
'
template_filename = "message.html"
else:
UpdateDb('UPDATE `posts` SET `IS_DELETED` = 0 WHERE `boardid` = %s AND `id` = %s LIMIT 1', (board['id'], path_split[6]))
if post['parentid'] != 0:
threadUpdated(post['parentid'])
else:
regenerateFrontPages()
if post['IS_DELETED'] == 2:
regenerateTrash()
message = _('Post successfully restored.')
logAction(staff_account['username'], _('Restored post %s') % ('/' + path_split[5] + '/' + path_split[6]) )
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` = %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(post['id'], None)
if post['parentid']:
threadUpdated(post['parentid'])
else:
regenerateFrontPages()
message = "Post %s eliminado permanentemente de la papelera" % ('/' + board['dir'] + '/' + str(post['id']))
logAction(staff_account['username'], message + ' desde papelera. Contenido: ' + post['message'] + ' IP: ' + post['ip'])
# Delete more than 1 post
if 'deleteall' in self.formdata:
return # TODO
deleted = 0
for key in self.formdata:
if key[:2] == '!i':
# Board where the post is
dir = key[2:].split('/')[0]
postid = key[2:].split('/')[1] # Post to delete
# Delete post start
post = FetchOne('SELECT `parentid`, `dir` FROM `posts` INNER JOIN `boards` ON posts.boardid = boards.id WHERE `dir` = \'' + _mysql.escape_string(dir) + '\' AND posts.id = \'' + _mysql.escape_string(postid) + '\' LIMIT 1')
if not post:
message = _('Unable to locate a post with that ID.')
else:
board = setBoard(dir)
deletePost(int(postid), None)
if post['parentid']:
threadUpdated(post['parentid'])
else:
regenerateFrontPages()
deleted += 1
# Delete post end
logAction(staff_account['username'], _('Permadeleted %s post(s).') % str(deleted))
message = _('Permadeleted %s post(s).') % str(deleted)
# Start
import math
pagesize = float(Settings.RECYCLEBIN_POSTS_PER_PAGE)
try:
currentpage = int(path_split[3])
except:
currentpage = 0
skip = False
if 'type' in self.formdata:
type = int(self.formdata["type"])
else:
type = 0
# Generate board list
boards = FetchAll('SELECT `name`, `dir` FROM `boards` ORDER BY `dir`')
for board in boards:
if 'board' in self.formdata and self.formdata['board'] == board['dir']:
board['checked'] = True
else:
board['checked'] = False
# Get type filter
if type != 0:
type_condition = "= " + str(type)
else:
type_condition = "!= 0"
# Table
if 'board' in self.formdata and self.formdata['board'] != 'all':
cboard = setBoard(self.formdata['board'])['dir']
posts = FetchAll("SELECT posts.id, posts.timestamp, timestamp_formatted, IS_DELETED, INET6_NTOA(posts.ip) AS ip, posts.message, dir, boardid FROM `posts` INNER JOIN `boards` ON boardid = boards.id WHERE `dir` = '%s' AND IS_DELETED %s ORDER BY `timestamp` DESC LIMIT %d, %d" % (cboard, type_condition, currentpage*pagesize, pagesize))
try:
totals = FetchOne("SELECT COUNT(id) AS count FROM `posts` WHERE IS_DELETED %s AND `boardid` = %s LIMIT 1" % (type_condition, posts[0]['boardid']) )
except:
skip = True
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" % (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,
'type': type,
'boards': boards,
'skip': skip}
if not skip:
# Calculate number of pages
total = totals["count"]
pages = int(math.ceil(total / pagesize))
# Create delete form
if 'board' in self.formdata and self.formdata['board'] != 'all':
board = setBoard(self.formdata['board'])['dir']
else:
board = None
navigator = ''
if currentpage > 0:
navigator += '< '
else:
navigator += '< '
for i in range(pages):
if i != currentpage:
navigator += ''+str(i)+' '
else:
navigator += str(i)+' '
if currentpage < (pages-1):
navigator += '> '
else:
navigator += '> '
template_values.update({'currentpage': currentpage,
'curboard': board,
'posts': posts,
'navigator': navigator})
# End recyclebin
elif path_split[2] == 'lockboard':
if not administrator:
return
try:
board_dir = path_split[3]
except:
board_dir = ''
if board_dir == '':
template_filename = "lockboard.html"
template_values = {'boards': boardlist()}
elif path_split[2] == 'boardlock':
board = setBoard(path_split[3])
if int(board['locked']):
# Si esta cerrado... abrir
board['locked'] = 0
updateBoardSettings()
message = _('Board opened successfully.')
template_filename = "message.html"
else:
# Si esta abierta, cerrar
board['locked'] = 1
updateBoardSettings()
message = _('Board closed successfully.')
template_filename = "message.html"
elif path_split[2] == 'addboard':
if not administrator:
return
action_taken = False
board_dir = ''
try:
if self.formdata['name'] != '':
board_dir = self.formdata['dir']
except:
pass
if board_dir != '':
action_taken = True
board_exists = FetchOne("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')
if not os.path.exists(Settings.IMAGES_DIR + board_dir):
os.mkdir(Settings.IMAGES_DIR + board_dir)
os.mkdir(Settings.IMAGES_DIR + board_dir + '/src')
os.mkdir(Settings.IMAGES_DIR + board_dir + '/thumb')
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 (%s, %s)",
(board_dir, self.formdata['name']))
board = setBoard(board_dir)
f = open(Settings.ROOT_DIR +
board['dir'] + '/.htaccess', 'w')
try:
f.write('DirectoryIndex index.html')
finally:
f.close()
regenerateFrontPages()
message = _('Board added')
template_filename = "message.html"
logAction(staff_account['username'], _(
'Added board %s') % ('/' + board['dir'] + '/'))
else:
message = _(
'There was a problem while making the directories.')
template_filename = "message.html"
else:
message = _(
'There is already a board with that directory.')
template_filename = "message.html"
if not action_taken:
template_filename = "addboard.html"
template_values = {}
elif path_split[2] == 'trim':
if not administrator:
return
board = setBoard(path_split[3])
trimThreads()
self.output = "done trimming"
return
elif path_split[2] == 'setexpires':
if not administrator:
return
board = setBoard(path_split[3])
parentid = int(path_split[4])
days = int(path_split[5])
t = time.time()
expires = int(t) + (days * 86400)
date_format = '%d/%m'
expires_formatted = datetime.datetime.fromtimestamp(
expires).strftime(date_format)
sql = "UPDATE posts SET expires = timestamp + (%s * 86400), expires_formatted = FROM_UNIXTIME((timestamp + (%s * 86400)), '%s') WHERE boardid = %s AND id = %s" % (
str(days), str(days), date_format, board["id"], str(parentid))
UpdateDb(sql)
self.output = "done " + sql
return
elif path_split[2] == 'fixflood':
if not administrator:
return
board = setBoard('zonavip')
threads = FetchAll(
"SELECT * FROM posts WHERE boardid = %s AND parentid = 0 AND subject LIKE 'querido mod%%'" % board['id'])
for thread in threads:
self.output += "%s
" % thread['id']
#deletePost(thread['id'], None)
return
elif path_split[2] == 'fixico':
if not administrator:
return
board = setBoard(path_split[3])
if board['dir'] != 'noticias':
return
threads = FetchAll("SELECT * FROM posts WHERE boardid = %s AND parentid = 0 AND message NOT LIKE ''
fname = Settings.ROOT_DIR + \
board["dir"] + "/kako/" + \
str(item["timestamp"]) + ".json"
if os.path.isfile(fname):
import json
with open(fname) as f:
thread = json.load(f)
#thread['posts'] = [dict(list(zip(thread['keys'], row))) for row in thread['posts']]
#if 'posterid' not in thread['keys']:
# for post in thread['posts']:
# half = post['timestamp_formatted'].split(' ID:')
# if len(half) > 1:
# post['timestamp_formatted'] = half[0]
# post['posterid'] = half[1]
# else:
# post['posterid'] = ''
#
# thread['keys'].append('posterid')
#if 'message' not in thread:
# thread['message'] = thread['posts'][0]['message']
# thread['keys'].append('message')
#thread['posts'] = [[row[key] for key in thread['keys']] for row in thread['posts']]
##raise UserError(thread)
#try:
# with open(fname, "w") as f:
# json.dump(thread, f, indent=0)
#except:
# raise UserError("Can't edit")
thread['posts'] = [dict(list(zip(thread['keys'], row))) for row in thread['posts']]
post_preview = cut_msg(thread['message'], 0)
page = renderTemplate("txt_archive.html", {"threads": [thread], "preview": post_preview}, False)
with open(Settings.ROOT_DIR + board["dir"] + "/kako/" + str(thread['timestamp']) + ".html", "w") as f:
f.write(page)
self.output += 'done' + str(time.time() - t) + '
'
else:
self.output += 'El hilo no existe.
'
elif path_split[2] == 'fixexpires':
if not administrator:
return
board = setBoard(path_split[3])
if int(board["maxage"]):
date_format = '%d/%m'
date_format_y = '%m/%Y'
if int(board["maxage"]) >= 365:
date_format = date_format_y
sql = "UPDATE posts SET expires = timestamp + (%s * 86400), expires_formatted = FROM_UNIXTIME((timestamp + (%s * 86400)), '%s') WHERE boardid = %s AND parentid = 0" % (
board["maxage"], board["maxage"], date_format, board["id"])
UpdateDb(sql)
alert_time = int(
round(int(board['maxage']) * Settings.MAX_AGE_ALERT))
sql = "UPDATE posts SET expires_alert = CASE WHEN UNIX_TIMESTAMP() > (expires - %d*86400) THEN 1 ELSE 0 END WHERE boardid = %s AND parentid = 0" % (alert_time,
board["id"])
UpdateDb(sql)
else:
sql = "UPDATE posts SET expires = 0, expires_formatted = '', expires_alert = 0 WHERE boardid = %s AND parentid = 0" % (
board["id"])
UpdateDb(sql)
self.output = "done"
return
elif path_split[2] == 'sepid':
if not administrator:
return
#sql = 'update posts set posterid = \'\''
#UpdateDb(sql)
board = setBoard(path_split[3])
#posts = FetchAll('SELECT * FROM `posts` WHERE `boardid` = %s LIMIT 5' % board['id'])
#for post in posts:
# self.output += str(post)
#return
posts = FetchAll('SELECT * FROM `posts` WHERE `boardid` = %s' % board['id'])
for post in posts:
if not post['posterid']:
splitted = post['timestamp_formatted'].split(' ID:')
self.output += splitted[0] + '
'
idhash = ''
if len(splitted) > 1:
self.output += splitted[1]
idhash = splitted[1]
self.output += '