from bottle import * from bottle.ext import beaker import bcrypt import difflib import shutil import threading import logging logging.basicConfig(level = logging.ERROR) session_opts = { 'session.type': 'dbm', 'session.data_dir': './app_session/', 'session.auto': 1 } app = beaker.middleware.SessionMiddleware(app(), session_opts) BaseRequest.MEMFILE_MAX = 1000 ** 4 r_ver = '2.5.0' from func import * from set_mark.mid_pas import mid_pas from set_mark.macro import savemark try: json_data = open('set.json').read() set_data = json.loads(json_data) except: while(1): new_json = [] print('DB 이름 : ', end = '') new_json += [input()] print('포트 : ', end = '') new_json += [input()] if(new_json[0] != '' and new_json[1] != ''): with open("set.json", "w") as f: f.write('{ "db" : "' + new_json[0] + '", "port" : "' + new_json[1] + '" }') json_data = open('set.json').read() set_data = json.loads(json_data) break else: print('모든 값을 입력하세요.') pass conn = sqlite3.connect(set_data['db'] + '.db') curs = conn.cursor() # 스킨 불러오기 부분 TEMPLATE_PATH.insert(0, skin_check(conn)) try: try: plus_all_data = '' start_replace = 0 curs.execute('select data from other where name = "css"') for m_lo in curs.fetchall(): plus_all_data += '\r\n' curs.execute('select data from other where name = "js"') for m_lo in curs.fetchall(): plus_all_data += '\r\n' if(plus_all_data != ''): curs.execute("insert into other (name, data) values ('head', ?)", [plus_all_data]) curs.execute("delete from other where name = 'css'") curs.execute("delete from other where name = 'js'") start_replace = 1 curs.execute('select user from custom') if(curs.fetchall()): curs.execute("select user from custom where user like ?", ['% (head)%']) if(not curs.fetchall()): curs.execute("select user, css from custom") for data_lo in curs.fetchall(): plus_all_data = '' if(re.search(' \(js\)$', data_lo[0])): name_data_is = data_lo[0].replace(' (js)', '') plus_all_data = '\r\n' else: name_data_is = data_lo[0] plus_all_data = '\r\n' curs.execute("select css from custom where user = ?", [name_data_is + ' (head)']) data_is_it = curs.fetchall() if(data_is_it): curs.execute("update custom set css = ? where user = ?", [data_is_it[0][0] + plus_all_data, name_data_is + ' (head)']) else: curs.execute("insert into custom (user, css) values (?, ?)", [name_data_is + ' (head)', plus_all_data]) curs.execute("delete from custom where user = ?", [data_lo[0]]) start_replace = 1 if(start_replace == 1): print('CSS, JS 데이터 변환') except: pass curs.execute("create table if not exists ok_login(ip text, sub text)") curs.execute("drop table if exists move") curs.execute("create table if not exists filter(name text, regex text, sub text)") try: curs.execute("alter table history add hide text default ''") curs.execute('select title, re from hidhi') for rep in curs.fetchall(): curs.execute("update history set hide = 'O' where title = ? and id = ?", [rep[0], rep[1]]) curs.execute("drop table if exists hidhi") except: pass conn.commit() except: pass # 이미지 폴더 생성 if(not os.path.exists('image')): os.makedirs('image') # 스킨 폴더 생성 if(not os.path.exists('views')): os.makedirs('views') def back_up(): try: shutil.copyfile(set_data['db'] + '.db', 'back_' + set_data['db'] + '.db') print('백업 성공') except: print('백업 오류') threading.Timer(60 * 60 * back_time, back_up).start() try: curs.execute('select data from other where name = "back_up"') back_up_time = curs.fetchall() back_time = int(back_up_time[0][0]) except: back_time = 0 if(back_time != 0): print(str(back_time) + '시간 간격으로 백업') if(__name__ == '__main__'): back_up() else: print('백업하지 않음') @route('/setup', method=['GET', 'POST']) def setup(): try: curs.execute("select title from data limit 1") except: curs.execute("create table if not exists data(title text, data text, acl text)") curs.execute("create table if not exists history(id text, title text, data text, date text, ip text, send text, leng text, hide text)") curs.execute("create table if not exists rd(title text, sub text, date text)") curs.execute("create table if not exists user(id text, pw text, acl text)") curs.execute("create table if not exists ban(block text, end text, why text, band text)") curs.execute("create table if not exists topic(id text, title text, sub text, data text, date text, ip text, block text, top text)") curs.execute("create table if not exists stop(title text, sub text, close text)") curs.execute("create table if not exists rb(block text, end text, today text, blocker text, why text)") curs.execute("create table if not exists back(title text, link text, type text)") curs.execute("create table if not exists agreedis(title text, sub text)") curs.execute("create table if not exists custom(user text, css text)") curs.execute("create table if not exists other(name text, data text)") curs.execute("create table if not exists alist(name text, acl text)") curs.execute("create table if not exists re_admin(who text, what text, time text)") curs.execute("create table if not exists alarm(name text, data text, date text)") curs.execute("create table if not exists ua_d(name text, ip text, ua text, today text, sub text)") curs.execute("create table if not exists ok_login(ip text, sub text)") curs.execute("create table if not exists filter(name text, regex text, sub text)") curs.execute("select name from alist where name = '소유자'") if(not curs.fetchall()): curs.execute("insert into alist (name, acl) values ('소유자', 'owner')") conn.commit() return(redirect('/')) @route('/del_alarm') def del_alarm(): curs.execute("delete from alarm where name = ?", [ip_check()]) conn.commit() return(redirect('/alarm')) @route('/alarm') def alarm(): ip = ip_check() if(re.search('(?:\.|:)', ip)): return(redirect('/login')) da = '' return(html_minify(template('index', imp = ['알림', wiki_set(conn, 1), custom(conn), other2([0, 0])], data = da, menu = [['user', '사용자']] ))) @route('/edit_set', method=['POST', 'GET']) @route('/edit_set/', method=['POST', 'GET']) def edit_set(num = 0): if(num != 0 and admin_check(conn, None, None) != 1): return(re_error(conn, '/ban')) if(num == 0): li_list = ['기본 설정', '문구 관련', '전역 HEAD', 'robots.txt', '구글 관련'] x = 0 li_data = '' for li in li_list: x += 1 li_data += ' * [[wiki:edit_set/' + str(x) + '|' + li + ']]\r\n' return(html_minify(template('index', imp = ['설정 편집', wiki_set(conn, 1), custom(conn), other2([0, 0])], data = namumark(conn, '', '[목차(없음)]\r\n' + \ '== 메뉴 ==\r\n' + \ li_data, 0, 0, 0), menu = [['manager', '관리자']] ))) elif(num == 1): if(request.method == 'POST'): curs.execute("update other set data = ? where name = ?", [request.forms.name, 'name']) curs.execute("update other set data = ? where name = ?", [request.forms.logo, 'logo']) curs.execute("update other set data = ? where name = 'frontpage'", [request.forms.frontpage]) curs.execute("update other set data = ? where name = 'license'", [request.forms.license]) curs.execute("update other set data = ? where name = 'upload'", [request.forms.upload]) curs.execute("update other set data = ? where name = 'skin'", [request.forms.skin]) curs.execute("update other set data = ? where name = 'edit'", [request.forms.edit]) curs.execute("update other set data = ? where name = 'reg'", [request.forms.reg]) curs.execute("update other set data = ? where name = 'ip_view'", [request.forms.ip_view]) curs.execute("update other set data = ? where name = 'back_up'", [request.forms.back_up]) curs.execute("update other set data = ? where name = 'all_title'", [request.forms.all_title]) conn.commit() TEMPLATE_PATH.insert(0, skin_check(conn)) admin_check(conn, None, 'edit_set') return(redirect('/edit_set/1')) else: i_list = ['name', 'logo', 'frontpage', 'license', 'upload', 'skin', 'edit', 'reg', 'ip_view', 'back_up', 'all_title'] n_list = ['무명위키', '', '위키:대문', 'CC 0', '2', '', 'normal', '', '', '0', ''] d_list = [] x = 0 for i in i_list: curs.execute('select data from other where name = ?', [i]) sql_d = curs.fetchall() if(sql_d): d_list += [sql_d[0][0]] else: curs.execute('insert into other (name, data) values (?, ?)', [i, n_list[x]]) d_list += [n_list[x]] x += 1 conn.commit() div = '' if(d_list[6] == 'login'): div += '' div += '' div += '' elif(d_list[6] == 'admin'): div += '' div += '' div += '' else: div += '' div += '' div += '' ch_1 = '' ch_2 = '' ch_3 = '' if(d_list[7]): ch_1 = 'checked="checked"' if(d_list[8]): ch_2 = 'checked="checked"' if(d_list[10]): ch_3 = 'checked="checked"' return(html_minify(template('index', imp = ['기본 설정', wiki_set(conn, 1), custom(conn), other2([0, 0])], data = '
\ 이름
\
\ 로고 (HTML)
\
\ 대문
\
\ 라이선스 (HTML)
\
\ 파일 크기 [메가]
\
\ 스킨
\
\ 전역 ACL
\
\ 가입불가
\ 아이피 비공개
\ 모든 문서 보기 비활성화
\ 백업 간격 [시간] (끄기 : 0) {재시작 필요}
\
\ \
', menu = [['edit_set', '설정 편집']] ))) elif(num == 2): if(request.method == 'POST'): curs.execute("update other set data = ? where name = ?", [request.forms.contract, 'contract']) conn.commit() admin_check(conn, None, 'edit_set') return(redirect('/edit_set/2')) else: i_list = ['contract'] n_list = [''] d_list = [] x = 0 for i in i_list: curs.execute('select data from other where name = ?', [i]) sql_d = curs.fetchall() if(sql_d): d_list += [sql_d[0][0]] else: curs.execute('insert into other (name, data) values (?, ?)', [i, n_list[x]]) d_list += [n_list[x]] x += 1 conn.commit() return(html_minify(template('index', imp = ['문구 관련', wiki_set(conn, 1), custom(conn), other2([0, 0])], data = '
\ 가입 약관
\
\ \
', menu = [['edit_set', '설정 편집']] ))) elif(num == 3): if(request.method == 'POST'): curs.execute("select name from other where name = 'head'") if(curs.fetchall()): curs.execute("update other set data = ? where name = 'head'", [request.forms.content]) else: curs.execute("insert into other (name, data) values ('head', ?)", [request.forms.content]) conn.commit() admin_check(conn, None, 'edit_set') return(redirect('/edit_set/3')) else: curs.execute("select data from other where name = 'head'") head = curs.fetchall() if(head): data = head[0][0] else: data = '' return(html_minify(template('index', imp = ['전역 HEAD', wiki_set(conn, 1), custom(conn), other2([0, 0])], data = '<style>CSS</style>
<script>JS</script>

\
\
\ \
', menu = [['edit_set', '설정 편집']] ))) elif(num == 4): if(request.method == 'POST'): curs.execute("select name from other where name = 'robot'") if(curs.fetchall()): curs.execute("update other set data = ? where name = 'robot'", [request.forms.content]) else: curs.execute("insert into other (name, data) values ('robot', ?)", [request.forms.content]) conn.commit() admin_check(conn, None, 'edit_set') return(redirect('/edit_set/4')) else: curs.execute("select data from other where name = 'robot'") robot = curs.fetchall() if(robot): data = robot[0][0] else: data = '' return(html_minify(template('index', imp = ['robots.txt', wiki_set(conn, 1), custom(conn), other2([0, 0])], data = '(보기)
\
\
\ \
', menu = [['edit_set', '설정 편집']] ))) elif(num == 5): if(request.method == 'POST'): curs.execute("update other set data = ? where name = 'recaptcha'", [request.forms.recaptcha]) curs.execute("update other set data = ? where name = 'sec_re'", [request.forms.sec_re]) conn.commit() admin_check(conn, None, 'edit_set') return(redirect('/edit_set/5')) else: i_list = ['recaptcha', 'sec_re'] n_list = ['', ''] d_list = [] x = 0 for i in i_list: curs.execute('select data from other where name = ?', [i]) sql_d = curs.fetchall() if(sql_d): d_list += [sql_d[0][0]] else: curs.execute('insert into other (name, data) values (?, ?)', [i, n_list[x]]) d_list += [n_list[x]] x += 1 conn.commit() return(html_minify(template('index', imp = ['구글 관련', wiki_set(conn, 1), custom(conn), other2([0, 0])], data = '
\ 리캡차 (HTML)
\
\ 리캡차 (비밀키)
\
\ \
', menu = [['edit_set', '설정 편집']] ))) else: return(redirect('/')) @route('/not_close_topic') def not_close_topic(): div = '' return(html_minify(template('index', imp = ['열린 토론 목록', wiki_set(conn, 1), custom(conn), other2([0, 0])], data = div, menu = [['manager', '관리자']] ))) @route('/image/') def static(name = None): if(os.path.exists(os.path.join('image', name))): return(static_file(name, root = 'image')) else: return(redirect('/')) @route('/acl_list') def acl_list(): div = '' return(html_minify(template('index', imp = ['ACL 문서 목록', wiki_set(conn, 1), custom(conn), other2([0, 0])], data = div, menu = [['other', '기타']] ))) @route('/admin_plus/', method=['POST', 'GET']) def admin_plus(name = None): if(request.method == 'POST'): if(admin_check(conn, None, 'admin_plus (' + name + ')') != 1): return(re_error(conn, '/error/3')) curs.execute("delete from alist where name = ?", [name]) if(request.forms.ban): curs.execute("insert into alist (name, acl) values (?, 'ban')", [name]) if(request.forms.mdel): curs.execute("insert into alist (name, acl) values (?, 'mdel')", [name]) if(request.forms.toron): curs.execute("insert into alist (name, acl) values (?, 'toron')", [name]) if(request.forms.check): curs.execute("insert into alist (name, acl) values (?, 'check')", [name]) if(request.forms.acl): curs.execute("insert into alist (name, acl) values (?, 'acl')", [name]) if(request.forms.hidel): curs.execute("insert into alist (name, acl) values (?, 'hidel')", [name]) if(request.forms.give): curs.execute("insert into alist (name, acl) values (?, 'give')", [name]) if(request.forms.owner): curs.execute("insert into alist (name, acl) values (?, 'owner')", [name]) conn.commit() return(redirect('/admin_plus/' + url_pas(name))) else: curs.execute('select acl from alist where name = ?', [name]) acl_list = curs.fetchall() data = '
    ' exist_list = ['', '', '', '', '', '', '', ''] for go in acl_list: if(go[0] == 'ban'): exist_list[0] = 'checked="checked"' elif(go[0] == 'mdel'): exist_list[1] = 'checked="checked"' elif(go[0] == 'toron'): exist_list[2] = 'checked="checked"' elif(go[0] == 'check'): exist_list[3] = 'checked="checked"' elif(go[0] == 'acl'): exist_list[4] = 'checked="checked"' elif(go[0] == 'hidel'): exist_list[5] = 'checked="checked"' elif(go[0] == 'give'): exist_list[6] = 'checked="checked"' elif(go[0] == 'owner'): exist_list[7] = 'checked="checked"' if(admin_check(conn, None, None) != 1): state = 'disabled' else: state = '' data += '
  • 차단
  • ' data += '
  • 많은 문서 삭제
  • ' data += '
  • 토론 관리
  • ' data += '
  • 사용자 검사
  • ' data += '
  • 문서 ACL
  • ' data += '
  • 역사 숨김
  • ' data += '
  • 권한 부여
  • ' data += '
  • 소유자
' return(html_minify(template('index', imp = ['관리 그룹 추가', wiki_set(conn, 1), custom(conn), other2([0, 0])], data = '
' + data + '
', menu = [['manager', '관리자']] ))) @route('/admin_list') def admin_list(): div = '
    ' curs.execute("select id, acl from user where not acl = 'user'") user_data = curs.fetchall() for data in user_data: name = ip_pas(conn, data[0]) + ' (' + data[1] + ')' div += '
  • ' + name + '
  • ' div += '
' return(html_minify(template('index', imp = ['관리자 목록', wiki_set(conn, 1), custom(conn), other2([0, 0])], data = div, menu = [['other', '기타']] ))) @route('/history//r//hidden') def history_hidden(name = None, num = None): if(admin_check(conn, 6, 'history_hidden (' + name + '#' + str(num) + ')') == 1): curs.execute("select title from history where title = ? and id = ? and hide = 'O'", [name, str(num)]) if(curs.fetchall()): curs.execute("update history set hide = '' where title = ? and id = ?", [name, str(num)]) else: curs.execute("update history set hide = 'O' where title = ? and id = ?", [name, str(num)]) conn.commit() return(redirect('/history/' + url_pas(name))) @route('/user_log') @route('/user_log/') def user_log(num = 1): if(num * 50 > 0): sql_num = num * 50 - 50 else: sql_num = 0 list_data = '
    ' admin_one = admin_check(conn, 1, None) curs.execute("select id from user limit ?, '50'", [str(sql_num)]) user_list = curs.fetchall() for data in user_list: if(admin_one == 1): curs.execute("select block from ban where block = ?", [data[0]]) ban_exist = curs.fetchall() if(ban_exist): ban_button = ' (해제)' else: ban_button = ' (차단)' else: ban_button = '' ip = ip_pas(conn, data[0]) list_data += '
  • ' + ip + ban_button + '
  • ' if(num == 1): curs.execute("select count(id) from user") user_count = curs.fetchall() if(user_count): count = user_count[0][0] else: count = 0 list_data += '
  • 이 위키에는 ' + str(count) + '명의 사람이 있습니다.
  • ' list_data += '

(이전) (이후)' return(html_minify(template('index', imp = ['사용자 가입 기록', wiki_set(conn, 1), custom(conn), other2([0, 0])], data = list_data, menu = [['other', '기타']] ))) @route('/admin_log') @route('/admin_log/') def user_log(num = 1): if(num * 50 > 0): sql_num = num * 50 - 50 else: sql_num = 0 list_data = '
    ' curs.execute("select who, what, time from re_admin order by time desc limit ?, '50'", [str(sql_num)]) get_list = curs.fetchall() for data in get_list: ip = ip_pas(conn, data[0]) list_data += '
  • ' + ip + ' / ' + data[1] + ' / ' + data[2] + '
  • ' list_data += '

주의 : 권한 사용 안하고 열람만 해도 기록되는 경우도 있습니다.
' list_data += '(이전) (이후)' return(html_minify(template('index', imp = ['관리자 권한 기록', wiki_set(conn, 1), custom(conn), other2([0, 0])], data = list_data, menu = [['other', '기타']] ))) @route('/give_log') @route('/give_log/') def give_log(num = 1): if(num * 50 > 0): sql_num = num * 50 - 50 else: sql_num = 0 list_data = '
    ' back = '' curs.execute("select distinct name from alist order by name asc limit ?, '50'", [str(sql_num)]) get_list = curs.fetchall() for data in get_list: if(back != data[0]): back = data[0] list_data += '
  • ' + data[0] + '
  • ' list_data += '

(생성)' list_data += '
(이전) (이후)' return(html_minify(template('index', imp = ['권한 목록', wiki_set(conn, 1), custom(conn), other2([0, 0])], data = list_data, menu = [['other', '기타']] ))) @route('/indexing') def indexing(): if(admin_check(conn, None, 'indexing') != 1): return(re_error(conn, '/error/3')) curs.execute("select name from sqlite_master where type in ('table', 'view') and name not like 'sqlite_%' union all select name from sqlite_temp_master where type in ('table', 'view') order by 1;") data = curs.fetchall() for table in data: print('----- ' + table[0] + ' -----') curs.execute('select sql from sqlite_master where name = ?', [table[0]]) cul = curs.fetchall() r_cul = re.findall('(?:([^ (]*) text)', str(cul[0])) for n_cul in r_cul: print(n_cul) sql = 'create index index_' + table[0] + '_' + n_cul + ' on ' + table[0] + '(' + n_cul + ')' try: curs.execute(sql) except: pass conn.commit() return(redirect('/')) @route('/xref/') @route('/xref//num/') def xref(name = None, num = 1): if(num * 50 > 0): sql_num = num * 50 - 50 else: sql_num = 0 div = '
    ' curs.execute("select link, type from back where title = ? and not type = 'cat' and not type = 'no' order by link asc limit ?, '50'", [name, str(sql_num)]) for data in curs.fetchall(): div += '
  • ' + data[0] + '' if(data[1]): if(data[1] == 'include'): side = '포함' elif(data[1] == 'file'): side = '파일' else: side = '넘겨주기' div += ' (' + side + ')' div += '
  • ' if(re.search('^틀:', data[0])): div += '
  • ' + data[0] + ' (역링크)
  • ' div += '

(이전) (이후)' return(html_minify(template('index', imp = [name, wiki_set(conn, 1), custom(conn), other2([' (역링크)', 0])], data = div, menu = [['w/' + url_pas(name), '문서']] ))) @route('/please') @route('/please/') def please(num = 1): if(num * 50 > 0): sql_num = num * 50 - 50 else: sql_num = 0 div = '
    ' var = '' curs.execute("select distinct title from back where type = 'no' order by title asc limit ?, '50'", [str(sql_num)]) for data in curs.fetchall(): if(var != data[0]): div += '
  • ' + data[0] + '
  • ' var = data[0] div += '

(이전) (이후)' return(html_minify(template('index', imp = ['필요한 문서', wiki_set(conn, 1), custom(conn), other2([0, 0])], data = div, menu = [['other', '기타']] ))) @route('/recent_discuss') @route('/recent_discuss/') def recent_discuss(tools = 'normal'): if(tools == 'normal' or tools == 'close'): div = '' if(tools == 'normal'): div += '(닫힌 토론)' m_sub = 0 else: div += '(열린 토론)' m_sub = ' (닫힘)' div += '
' else: return(redirect('/')) curs.execute("select title, sub, date from rd order by date desc limit 50") for data in curs.fetchall(): title = html.escape(data[0]) sub = html.escape(data[1]) close = 0 if(tools == 'normal'): curs.execute("select title from stop where title = ? and sub = ? and close = 'O'", [data[0], data[1]]) if(curs.fetchall()): close = 1 else: curs.execute("select title from stop where title = ? and sub = ? and close = 'O'", [data[0], data[1]]) if(not curs.fetchall()): close = 1 if(close == 0): div += '' else: div += '
토론명시간
' + title + ' (' + sub + ')' + data[2] + '
' return(html_minify(template('index', imp = ['최근 토론내역', wiki_set(conn, 1), custom(conn), other2([m_sub, 0])], data = div, menu = 0 ))) @route('/block_log') @route('/block_log/') @route('/block_log//') @route('//') @route('///') def block_log(num = 1, name = None, tool = None, tool2 = None): if(num * 50 > 0): sql_num = num * 50 - 50 else: sql_num = 0 div = '' if(not name): if(not tool2): div = '(차단자 검색)(관리자 검색)
(아이피)(가입자)(영구)(기간)(해제)
' + div sub = 0 menu = [['other', '기타']] curs.execute("select why, block, blocker, end, today from rb order by today desc limit ?, '50'", [str(sql_num)]) else: menu = [['block_log', '일반']] if(tool2 == 'ip'): sub = ' (아이피)' curs.execute("select why, block, blocker, end, today from rb where (block like ? or block like ?) order by today desc limit ?, '50'", ['%.%', '%:%', str(sql_num)]) elif(tool2 == 'user'): sub = ' (가입자)' curs.execute("select why, block, blocker, end, today from rb where not (block like ? or block like ?) order by today desc limit ?, '50'", ['%.%', '%:%', str(sql_num)]) elif(tool2 == 'never_end'): sub = '(영구)' curs.execute("select why, block, blocker, end, today from rb where not end like ? and not end like ? order by today desc limit ?, '50'", ['%:%', '%해제%', str(sql_num)]) elif(tool2 == 'end'): sub = '(해제)' curs.execute("select why, block, blocker, end, today from rb where end = ? order by today desc limit ?, '50'", ['해제', str(sql_num)]) else: sub = '(기간)' curs.execute("select why, block, blocker, end, today from rb where end like ? order by today desc limit ?, '50'", ['%:%', str(sql_num)]) else: menu = [['block_log', '일반']] if(tool == 'block_user'): sub = ' (차단자)' curs.execute("select why, block, blocker, end, today from rb where block = ? order by today desc limit ?, '50'", [name, str(sql_num)]) else: sub = ' (관리자)' curs.execute("select why, block, blocker, end, today from rb where blocker = ? order by today desc limit ?, '50'", [name, str(sql_num)]) for data in curs.fetchall(): why = html.escape(data[0]) if(why == ''): why = '
' b = re.search("^([0-9]{1,3}\.[0-9]{1,3})$", data[1]) if(b): ip = data[1] + ' (대역)' else: ip = ip_pas(conn, data[1]) if(data[3] != ''): end = data[3] else: end = '무기한' div += '' div += '' div += '
차단자관리자기간
' + ip + '' + ip_pas(conn, data[2]) + '시작 : ' + data[4] + '
끝 : ' + end + '
' + why + '

' div += '(이전) (이후)' return(html_minify(template('index', imp = ['차단 기록', wiki_set(conn, 1), custom(conn), other2([sub, 0])], data = div, menu = menu ))) @route('/search', method=['POST']) def search(): return(redirect('/search/' + url_pas(request.forms.search))) @route('/goto', method=['POST']) def goto(): curs.execute("select title from data where title = ?", [request.forms.search]) data = curs.fetchall() if(data): return(redirect('/w/' + url_pas(request.forms.search))) else: return(redirect('/search/' + url_pas(request.forms.search))) @route('/search/') @route('/search//') def deep_search(name = None, num = 1): if(num * 50 > 0): sql_num = num * 50 - 50 else: sql_num = 0 div = '
    ' div_plus = '' no = 0 curs.execute("select distinct title from data where title like ? or data like ? order by case when title like ? then 1 else 2 end limit ?, '50'", ['%' + name + '%', '%' + name + '%', '%' + name + '%', str(sql_num)]) all_list = curs.fetchall() curs.execute("select title from data where title = ?", [name]) exist = curs.fetchall() if(exist): div = '
    • 문서로 바로가기

    • ' else: div = '
      • 문서가 없습니다. 바로가기

      • ' start = 2 if(all_list): for data in all_list: try: var_re = re.search(name, data[0]) except: var_re = re.search('\\' + name, data[0]) if(var_re): if(no == 0): div_plus += '
      • ' + data[0] + ' (제목)
      • ' start = 0 else: if(start == 0 and div_plus != ''): start = 1 div_plus += '
        ' div_plus += '
      • ' + data[0] + ' (내용)
      • ' else: no = 1 if(start == 0 and div_plus != ''): start = 1 div_plus += '
        ' div_plus += '
      • ' + data[0] + ' (내용)
      • ' else: div += '
      • 검색 결과 없음
      • ' div += div_plus div += '

      (이전) (이후)' return(html_minify(template('index', imp = [name, wiki_set(conn, 1), custom(conn), other2([' (검색)', 0])], data = div, menu = 0 ))) @route('/raw/') @route('/raw//r/') @route('/topic//sub//raw/') def raw_view(name = None, sub_t = None, num = None): v_name = name sub = ' (원본)' if(not sub_t and num): curs.execute("select title from history where title = ? and id = ? and hide = 'O'", [name, str(num)]) hid = curs.fetchall() if(hid and admin_check(conn, 6, None) != 1): return(re_error(conn, '/error/3')) curs.execute("select data from history where title = ? and id = ?", [name, str(num)]) sub += ' (' + str(num) + '판)' menu = [['history/' + url_pas(name), '역사']] elif(sub_t): curs.execute("select data from topic where id = ? and title = ? and sub = ? and block = ''", [str(num), name, sub_t]) v_name = '토론 원본' sub = ' (' + str(num) + '번)' menu = [['topic/' + url_pas(name) + '/sub/' + url_pas(sub_t) + '#' + str(num), '토론']] else: curs.execute("select data from data where title = ?", [name]) menu = [['w/' + url_pas(name), '문서']] data = curs.fetchall() if(data): p_data = html.escape(data[0][0]) p_data = '' return(html_minify(template('index', imp = [v_name, wiki_set(conn, 1), custom(conn), other2([sub, 0])], data = p_data, menu = menu ))) else: return(redirect('/w/' + url_pas(name))) @route('/revert//r/', method=['POST', 'GET']) def revert(name = None, num = None): ip = ip_check() can = acl_check(conn, name) today = get_time() if(request.method == 'POST'): if(captcha_post(request.forms.get('g-recaptcha-response'), conn) == 1): return(re_error(conn, '/error/13')) else: captcha_post('', conn, 0) curs.execute("select title from history where title = ? and id = ? and hide = 'O'", [name, str(num)]) if(curs.fetchall() and admin_check(conn, 6, None) != 1): return(re_error(conn, '/error/3')) if(can == 1): return(re_error(conn, '/ban')) curs.execute("delete from back where link = ?", [name]) conn.commit() curs.execute("select data from history where title = ? and id = ?", [name, str(num)]) data = curs.fetchall() if(data): curs.execute("select data from data where title = ?", [name]) d = curs.fetchall() if(d): leng = leng_check(len(d[0][0]), len(data[0][0])) curs.execute("update data set data = ? where title = ?", [data[0][0], name]) else: leng = '+' + str(len(data[0][0])) curs.execute("insert into data (title, data, acl) values (?, ?, '')", [name, data[0][0]]) history_plus(conn, name, data[0][0], today, ip, request.forms.send + ' (' + str(num) + '판)', leng) namumark(conn, name, data[0][0], 1, 0, 0) conn.commit() return(redirect('/w/' + url_pas(name))) else: curs.execute("select title from history where title = ? and id = ? and hide = 'O'", [name, str(num)]) hid = curs.fetchall() if(hid and admin_check(conn, 6, None) != 1): return(re_error(conn, '/error/3')) if(can == 1): return(re_error(conn, '/ban')) curs.execute("select title from history where title = ? and id = ?", [name, str(num)]) if(not curs.fetchall()): return(redirect('/w/' + url_pas(name))) custom_data = custom(conn) captcha = captcha_get(conn) if(custom_data[2] == 0): ip_warring = '비 로그인 상태입니다. 비 로그인으로 진행 시 아이피가 역사에 기록됩니다.
      ' else: ip_warring = '' return(html_minify(template('index', imp = [name, wiki_set(conn, 1), custom_data, other2([' (되돌리기)', 0])], data = ip_warring + ' \
      \
      \ ' + captcha + ' \ \
      ', menu = [['history/' + url_pas(name), '역사'], ['recent_changes', '최근 변경']] ))) @route('/big_delete', method=['POST', 'GET']) def big_delete(): if(admin_check(conn, 2, 'big_delete') != 1): return(re_error(conn, '/error/3')) if(request.method == 'POST'): today = get_time() ip = ip_check() data = request.forms.content + '\r\n' m = re.findall('(.*)\r\n', data) for g in m: curs.execute("select data from data where title = ?", [g]) d = curs.fetchall() if(d): curs.execute("delete from back where title = ?", [g]) leng = '-' + str(len(d[0][0])) curs.execute("delete from data where title = ?", [g]) history_plus(conn, g, '', today, ip, request.forms.send + ' (대량 삭제)', leng) data = re.sub('(.*)\r\n', '', data, 1) conn.commit() return(redirect('/')) else: return(html_minify(template('index', imp = ['많은 문서 삭제', wiki_set(conn, 1), custom(conn), other2([0, 0])], data = '문서명 A
      문서명 B
      문서명 C
      이런 식으로 적으세요.

      \
      \
      \
      \ \
      ', menu = [['manager', '관리자']] ))) @route('/edit_filter') def edit_filter(): div = '
        ' curs.execute("select name from filter") data = curs.fetchall() for data_list in data: div += '
      • ' + data_list[0] + '
      • ' div += '
      ' div += '
      (추가)' return(html_minify(template('index', imp = ['편집 필터 목록', wiki_set(conn, 1), custom(conn), other2([0, 0])], data = div, menu = [['manager', '관리자']] ))) @route('/edit_filter//delete', method=['POST', 'GET']) def delete_edit_filter(name = None): if(admin_check(conn, 1, 'edit_filter delete') != 1): return(re_error('/error/3')) curs.execute("delete from filter where name = ?", [name]) conn.commit() return(redirect('/edit_filter')) @route('/edit_filter/', method=['POST', 'GET']) def set_edit_filter(name = None): if(request.method == 'POST'): if(admin_check(conn, 1, 'edit_filter edit') != 1): return(re_error('/error/3')) if(request.forms.day == '00'): end = '' elif(request.forms.day == '09'): end = 'X' else: end = request.forms.day + ' ' + request.forms.hour + ':' + request.forms.minu curs.execute("select name from filter where name = ?", [name]) if(curs.fetchall()): curs.execute("update filter set regex = ?, sub = ? where name = ?", [request.forms.content, end, name]) else: curs.execute("insert into filter (name, regex, sub) values (?, ?, ?)", [name, request.forms.content, end]) conn.commit() return(redirect('/edit_filter/' + url_pas(name))) else: curs.execute("select regex, sub from filter where name = ?", [name]) exist = curs.fetchall() if(exist): textarea = exist[0][0] match = re.search("^([^ ]+) ([^:]+):([^:]+)$", exist[0][1]) if(match): end_data = match.groups() else: end_data = ['', '', ''] else: textarea = '' end_data = ['', '', ''] if(admin_check(conn, 1, None) != 1): stat = 'disabled' else: stat = '' day = '' if(exist[0][1] == 'X'): day += '' else: day += '' for i in range(0, 32): if(str(i) == end_data[0]): day += '' else: day += '' hour = '' for i in range(0, 24): if(str(i) == end_data[1]): hour += '' else: hour += '' minu = '' for i in range(0, 61): if(str(i) == end_data[2]): minu += '' else: minu += '' data = ' 일 ' data += ' 시 ' data += ' 분 동안
      ' return(html_minify(template('index', imp = [name, wiki_set(conn, 1), custom(conn), other2([' (편집 필터)', 0])], data = '
      \ ' + data + ' \
      \ \
      ', menu = [['edit_filter', '목록'], ['edit_filter/' + url_pas(name) + '/delete', '삭제']] ))) @route('/edit/', method=['POST', 'GET']) @route('/edit//from/', method=['POST', 'GET']) @route('/edit//section/', method=['POST', 'GET']) def edit(name = None, name2 = None, num = None): ip = ip_check() can = acl_check(conn, name) if(can == 1): return(re_error(conn, '/ban')) if(request.method == 'POST'): if(admin_check(conn, 1, 'edit_filter pass') != 1): curs.execute("select regex, sub from filter") data = curs.fetchall() for data_list in data: match = re.compile(data_list[0]) if(match.search(request.forms.content)): print(data_list[1]) if(data_list[1] == 'X'): rb_plus(conn, ip, '', get_time(), '도구:편집 필터', '편집 필터에 의한 차단') curs.execute("insert into ban (block, end, why, band) values (?, '', ?, '')", [ip, '편집 필터에 의한 차단']) elif(not data_list[1] == ''): match = re.search("^([^ ]+) ([^:]+):([^:]+)$", data_list[1]) end_data = match.groups() match = re.search("^([^-]+)-([^-]+)-([^ ]+) ([^:]+):([^:]+):(.+)$", get_time()) time_data = match.groups() if(int(time_data[2]) + int(end_data[0]) > 29): month = int(time_data[1]) + 1 day = int(time_data[2]) + int(end_data[0]) - 30 if(month > 12): year = int(time_data[0]) + 1 month -= 12 else: year = int(time_data[0]) else: month = int(time_data[1]) day = int(time_data[2]) + int(end_data[0]) year = int(time_data[0]) if(int(time_data[3]) + int(end_data[1]) > 23): day += 1 hour = int(time_data[3]) + int(end_data[1]) - 24 else: hour = int(time_data[3]) + int(end_data[1]) if(int(time_data[4]) + int(end_data[2]) > 59): hour += 1 minu = int(time_data[4]) + int(end_data[2]) - 60 else: minu = int(time_data[4]) + int(end_data[2]) time_list = [month, day, hour, minu] num = 0 for time_fix in time_list: if(not re.search("[0-9]{2}", str(time_fix))): time_list[num] = '0' + str(time_fix) else: time_list[num] = str(time_fix) num += 1 end = str(year) + '-' + time_list[0] + '-' + time_list[1] + ' ' + time_list[2] + ':' + time_list[3] + ':' + time_data[5] rb_plus(conn, ip, end, get_time(), '도구:편집 필터', '편집 필터에 의한 차단') curs.execute("insert into ban (block, end, why, band) values (?, ?, ?, '')", [ip, end, '편집 필터에 의한 차단']) conn.commit() return(re_error(conn, '/error/21')) if(captcha_post(request.forms.get('g-recaptcha-response'), conn) == 1): return(re_error(conn, '/error/13')) else: captcha_post('', conn, 0) if(len(request.forms.send) > 500): return(re_error(conn, '/error/15')) if(request.forms.otent == request.forms.content): return(re_error(conn, '/error/18')) today = get_time() content = savemark(request.forms.content) curs.execute("select data from data where title = ?", [name]) old = curs.fetchall() if(old): if(not num and request.forms.otent != old[0][0]): return(re_error(conn, '/error/12')) leng = leng_check(len(request.forms.otent), len(content)) if(num): content = old[0][0].replace(request.forms.otent, content) curs.execute("update data set data = ? where title = ?", [content, name]) else: leng = '+' + str(len(content)) curs.execute("insert into data (title, data, acl) values (?, ?, '')", [name, content]) history_plus(conn, name, content, today, ip, send_p(request.forms.send), leng) curs.execute("delete from back where link = ?", [name]) curs.execute("delete from back where title = ? and type = 'no'", [name]) namumark(conn, name, content, 1, 0, 0) conn.commit() return(redirect('/w/' + url_pas(name))) else: curs.execute("select data from data where title = ?", [name]) new = curs.fetchall() if(new): if(num): i = 0 j = 0 data = new[0][0] + '\r\n' while(1): m = re.search("((?:={1,6})\s?(?:[^=]*)\s?(?:={1,6})(?:\s+)?\n(?:(?:(?:(?!(?:={1,6})\s?(?:[^=]*)\s?(?:={1,6})(?:\s+)?\n).)*)(?:\n)?)+)", data) if(m): if(i == num - 1): g = m.groups() data = re.sub("\r\n$", "", g[0]) break else: data = re.sub("((?:={1,6})\s?(?:[^=]*)\s?(?:={1,6})(?:\s+)?\n(?:(?:(?:(?!(?:={1,6})\s?(?:[^=]*)\s?(?:={1,6})(?:\s+)?\n).)*)(?:\n)?)+)", "", data, 1) i += 1 else: j = 1 break if(j == 0): data = re.sub("\r\n$", "", data) else: data = new[0][0] else: data = '' if(num): action = '/section/' + str(num) else: action = '' data2 = data if(not num): get_name = '
      \ \ \

      ' else: get_name = '' captcha = captcha_get(conn) if(name2): curs.execute("select data from data where title = ?", [name2]) get_data = curs.fetchall() if(get_data): data = get_data[0][0] get_name = '' return(html_minify(template('index', imp = [name, wiki_set(conn, 1), custom(conn), other2([' (수정)', 0])], data = get_name + ' \
      \ \
      \
      \ ' + captcha + ' \ \ \
      ', menu = [['w/' + url_pas(name), '문서']] ))) @route('/edit_get/', method=['POST']) def edit_get(name = None): return(redirect('/edit/' + url_pas(name) + '/from/' + url_pas(request.forms.name))) @route('/preview/', method=['POST']) @route('/preview//section/', method=['POST']) def preview(name = None, num = None): if(captcha_post(request.forms.get('g-recaptcha-response'), conn) == 1): return(re_error(conn, '/error/13')) else: captcha_post('', conn, 0) ip = ip_check() can = acl_check(conn, name) captcha = captcha_get(conn) if(can == 1): return(re_error(conn, '/ban')) newdata = request.forms.content newdata = re.sub('^#(?:redirect|넘겨주기) (?P[^\n]*)', ' * [[\g]] 문서로 넘겨주기', newdata) enddata = namumark(conn, name, newdata, 0, 0, 0) if(num): action = '/section/' + str(num) else: action = '' return(html_minify(template('index', imp = [name, wiki_set(conn, 1), custom(conn), other2([' (미리보기)', 0])], data = '
      \ \
      \
      \ ' + captcha + ' \ \ \

      ' + enddata, menu = [['w/' + url_pas(name), '문서']] ))) @route('/delete/', method=['POST', 'GET']) def delete(name = None): ip = ip_check() can = acl_check(conn, name) if(can == 1): return(re_error(conn, '/ban')) if(request.method == 'POST'): if(captcha_post(request.forms.get('g-recaptcha-response'), conn) == 1): return(re_error(conn, '/error/13')) else: captcha_post('', conn, 0) curs.execute("select data from data where title = ?", [name]) data = curs.fetchall() if(data): today = get_time() leng = '-' + str(len(data[0][0])) history_plus(conn, name, '', today, ip, request.forms.send + ' (삭제)', leng) curs.execute("select title, link from back where title = ? and not type = 'cat' and not type = 'no'", [name]) for data in curs.fetchall(): curs.execute("insert into back (title, link, type) values (?, ?, 'no')", [data[0], data[1]]) curs.execute("delete from back where link = ?", [name]) curs.execute("delete from data where title = ?", [name]) conn.commit() return(redirect('/w/' + url_pas(name))) else: curs.execute("select title from data where title = ?", [name]) if(not curs.fetchall()): return(redirect('/w/' + url_pas(name))) custom_data = custom(conn) captcha = captcha_get(conn) if(custom_data[2] == 0): ip_warring = '비 로그인 상태입니다. 비 로그인으로 진행 시 아이피가 역사에 기록됩니다.
      ' else: ip_warring = '' return(html_minify(template('index', imp = [name, wiki_set(conn, 1), custom_data, other2([' (삭제)', 0])], data = '
      \ ' + ip_warring + ' \
      \ ' + captcha + ' \ \
      ', menu = [['w/' + url_pas(name), '문서']] ))) @route('/move_data/') @route('/move_data//num/') def move_data(name = None, num = 1): if(num * 50 > 0): sql_num = num * 50 - 50 else: sql_num = 0 data = '
      (이전) (이후)' return(html_minify(template('index', imp = [name, wiki_set(conn, 1), custom(conn), other2([' (이동 기록)', 0])], data = data, menu = [['history/' + url_pas(name), '역사']] ))) @route('/move/', method=['POST', 'GET']) def move(name = None): ip = ip_check() can = acl_check(conn, name) today = get_time() if(can == 1): return(re_error(conn, '/ban')) if(request.method == 'POST'): if(captcha_post(request.forms.get('g-recaptcha-response'), conn) == 1): return(re_error(conn, '/error/13')) else: captcha_post('', conn, 0) curs.execute("select title from history where title = ?", [request.forms.title]) if(curs.fetchall()): return(re_error(conn, '/error/19')) curs.execute("select data from data where title = ?", [name]) data = curs.fetchall() leng = '0' if(data): curs.execute("update data set title = ? where title = ?", [request.forms.title, name]) curs.execute("update back set link = ? where link = ?", [request.forms.title, name]) d = data[0][0] else: d = '' history_plus(conn, name, d, today, ip, request.forms.send + ' (' + name + ' - ' + request.forms.title + ' 이동)', leng) curs.execute("select title, link from back where title = ? and not type = 'cat' and not type = 'no'", [name]) for data in curs.fetchall(): curs.execute("insert into back (title, link, type) values (?, ?, 'no')", [data[0], data[1]]) curs.execute("update history set title = ? where title = ?", [request.forms.title, name]) conn.commit() return(redirect('/w/' + url_pas(request.forms.title))) else: custom_data = custom(conn) captcha = captcha_get(conn) if(custom_data[2] == 0): ip_warring = '비 로그인 상태입니다. 비 로그인으로 진행 시 아이피가 역사에 기록됩니다.
      ' else: ip_warring = '' return(html_minify(template('index', imp = [name, wiki_set(conn, 1), custom_data, other2([' (이동)', 0])], data = '
      \ ' + ip_warring + ' \
      \
      \ ' + captcha + ' \ \
      ', menu = [['w/' + url_pas(name), '문서']] ))) @route('/other') def other(): return(html_minify(template('index', imp = ['기타 메뉴', wiki_set(conn, 1), custom(conn), other2([0, 0])], data = namumark(conn, '', '[목차(없음)]\r\n' + \ '== 기록 ==\r\n' + \ ' * [[wiki:block_log|차단 기록]]\r\n' + \ ' * [[wiki:user_log|가입 기록]]\r\n' + \ ' * [[wiki:admin_log|권한 기록]]\r\n' + \ ' * [[wiki:manager/6|편집 기록]]\r\n' + \ ' * [[wiki:manager/7|토론 기록]]\r\n' + \ '== 목록 ==\r\n' + \ ' * [[wiki:admin_list|관리자 목록]]\r\n' + \ ' * [[wiki:give_log|권한 목록]]\r\n' + ' * [[wiki:not_close_topic|열린 토론 목록]]\r\n' + \ '== 기타 ==\r\n' + \ ' * [[wiki:title_index|모든 문서]]\r\n' + \ ' * [[wiki:acl_list|ACL 문서]]\r\n' + \ ' * [[wiki:please|필요한 문서]]\r\n' + \ ' * [[wiki:upload|파일 올리기]]\r\n' + \ ' * [[wiki:manager/10|문서 검색]]\r\n' + \ '== 관리자 ==\r\n' + \ ' * [[wiki:manager/1|관리자 메뉴]]\r\n' + \ '== 버전 ==\r\n' + \ ' * 이 오픈나무는 [[https://github.com/2DU/openNAMU/blob/SQLite/version.md|' + r_ver + ']]판 입니다.', 0, 0, 0), menu = 0 ))) @route('/manager', method=['POST', 'GET']) @route('/manager/', method=['POST', 'GET']) def manager(num = 1): title_list = [['문서 ACL', '문서명', 'acl'], ['사용자 검사', 0, 'check'], ['사용자 차단', 0, 'ban'], ['권한 주기', 0, 'admin'], ['편집 기록', 0, 'record'], ['토론 기록', 0, 'topic_record'], ['그룹 생성', '그룹명', 'admin_plus'], ['편집 필터 생성', '필터명', 'edit_filter'], ['문서 검색', '문서명', 'search'], ['차단자 검색', 0, 'block_user'], ['관리자 검색', 0, 'block_admin']] if(num == 1): return(html_minify(template('index', imp = ['관리자 메뉴', wiki_set(conn, 1), custom(conn), other2([0, 0])], data = namumark(conn, '', '[목차(없음)]\r\n' + \ '== 목록 ==\r\n' + \ ' * [[wiki:manager/2|문서 ACL]]\r\n' + \ ' * [[wiki:manager/3|사용자 검사]]\r\n' + \ ' * [[wiki:manager/100|사용자 비교]]\r\n' + \ ' * [[wiki:manager/4|사용자 차단]]\r\n' + \ ' * [[wiki:manager/5|권한 주기]]\r\n' + \ ' * [[wiki:big_delete|여러 문서 삭제]]\r\n' + \ ' * [[wiki:edit_filter|편집 필터]]\r\n' + \ '== 소유자 ==\r\n' + \ ' * [[wiki:indexing|인덱싱]]\r\n' + \ ' * [[wiki:manager/8|관리 그룹 생성]]\r\n' + \ ' * [[wiki:edit_set|설정 편집]]\r\n' + \ '== 기타 ==\r\n' + \ ' * 이 메뉴에 없는 기능은 해당 문서의 역사나 토론에서 바로 사용 가능함', 0, 0, 0), menu = [['other', '기타']] ))) elif(num in range(2, 13)): if(request.method == 'POST'): return(redirect('/' + title_list[(num - 2)][2] + '/' + url_pas(request.forms.name))) else: if(title_list[(num - 2)][1] == 0): placeholder = '사용자명' else: placeholder = title_list[(num - 2)][1] return(html_minify(template('index', imp = [title_list[(num - 2)][0], wiki_set(conn, 1), custom(conn), other2([0, 0])], data = '
      \
      \ \
      ', menu = [['manager', '관리자']] ))) elif(num == 100): if(request.method == 'POST'): return(redirect('/check/' + url_pas(request.forms.name) + '/' + url_pas(request.forms.name2))) else: return(html_minify(template('index', imp = ['검사', wiki_set(conn, 1), custom(conn), other2([0, 0])], data = '
      \
      \
      \ \
      ', menu = [['manager', '관리자']] ))) else: return(redirect('/')) @route('/title_index') @route('/title_index//') def title_index(num = 100, page = 1): if(page * num > 0): sql_num = page * num - num else: sql_num = 0 if(num != 0): all_list = sql_num + 1 else: all_list = 1 if(num > 1000): return(re_error(conn, '/error/3')) data = '
        (전체) (250) (500) (1000)
        ' if(num == 0): curs.execute("select data from other where name = 'all_title'") all_title_can = curs.fetchall() if(all_title_can and all_title_can[0][0] != ''): return(re_error(conn, '/error/3')) curs.execute("select title from data order by title asc") else: curs.execute("select title from data order by title asc limit ?, ?", [str(sql_num), str(num)]) title_list = curs.fetchall() for list_data in title_list: data += '
      • ' + str(all_list) + '. ' + list_data[0] + '
      • ' all_list += 1 if(page == 1): count_end = [] curs.execute("select count(title) from data") count = curs.fetchall() if(count): count_end += [count[0][0]] else: count_end += [0] sql_list = ['틀:', '분류:', '사용자:', '파일:'] for sql in sql_list: curs.execute("select count(title) from data where title like ?", [sql + '%']) count = curs.fetchall() if(count): count_end += [count[0][0]] else: count_end += [0] count_end += [count_end[0] - count_end[1] - count_end[2] - count_end[3] - count_end[4]] data += '
      • 이 위키에는 총 ' + str(count_end[0]) + '개의 문서가 있습니다.

      • ' data += '
      • 틀 문서는 총 ' + str(count_end[1]) + '개의 문서가 있습니다.
      • ' data += '
      • 분류 문서는 총 ' + str(count_end[2]) + '개의 문서가 있습니다.
      • ' data += '
      • 사용자 문서는 총 ' + str(count_end[3]) + '개의 문서가 있습니다.
      • ' data += '
      • 파일 문서는 총 ' + str(count_end[4]) + '개의 문서가 있습니다.
      • ' data += '
      • 나머지 문서는 총 ' + str(count_end[5]) + '개의 문서가 있습니다.
      • ' if(num != 0): data += '

      (이전) (이후)' if(' (' + str(num) + '개)' == ' (0개)'): sub = 0 else: sub = ' (' + str(num) + '개)' return(html_minify(template('index', imp = ['모든 문서', wiki_set(conn, 1), custom(conn), other2([sub, 0])], data = data, menu = [['other', '기타']] ))) @route('/topic//sub//b/') def topic_block(name = None, sub = None, num = None): if(admin_check(conn, 3, 'blind (' + name + ' - ' + sub + '#' + str(num) + ')') != 1): return(re_error(conn, '/error/3')) curs.execute("select block from topic where title = ? and sub = ? and id = ?", [name, sub, str(num)]) block = curs.fetchall() if(block): if(block[0][0] == 'O'): curs.execute("update topic set block = '' where title = ? and sub = ? and id = ?", [name, sub, str(num)]) else: curs.execute("update topic set block = 'O' where title = ? and sub = ? and id = ?", [name, sub, str(num)]) rd_plus(conn, name, sub, get_time()) conn.commit() return(redirect('/topic/' + url_pas(name) + '/sub/' + url_pas(sub) + '#' + str(num))) @route('/topic//sub//notice/') def topic_top(name = None, sub = None, num = None): if(admin_check(conn, 3, 'notice (' + name + ' - ' + sub + '#' + str(num) + ')') != 1): return(re_error(conn, '/error/3')) curs.execute("select * from topic where title = ? and sub = ? and id = ?", [name, sub, str(num)]) topic_data = curs.fetchall() if(topic_data): curs.execute("select top from topic where id = ? and title = ? and sub = ?", [str(num), name, sub]) top_data = curs.fetchall() if(top_data): if(top_data[0][0] == 'O'): curs.execute("update topic set top = '' where title = ? and sub = ? and id = ?", [name, sub, str(num)]) else: curs.execute("update topic set top = 'O' where title = ? and sub = ? and id = ?", [name, sub, str(num)]) rd_plus(conn, name, sub, get_time()) conn.commit() return(redirect('/topic/' + url_pas(name) + '/sub/' + url_pas(sub) + '#' + str(num))) @route('/topic//sub//tool/') def topic_stop(name = None, sub = None, tool = None): if(tool == 'close'): set_list = ['O', '', '토론 닫기', '토론 열림'] elif(tool == 'stop'): set_list = ['', 'O', '토론 정지', '토론 재개'] elif(tool == 'agree'): pass else: return(redirect('/topic/' + url_pas(name) + '/sub/' + url_pas(sub))) if(admin_check(conn, 3, 'topic ' + tool + ' (' + name + ' - ' + sub + ')') != 1): return(re_error(conn, '/error/3')) ip = ip_check() time = get_time() curs.execute("select id from topic where title = ? and sub = ? order by id + 0 desc limit 1", [name, sub]) topic_check = curs.fetchall() if(topic_check): if(tool == 'agree'): curs.execute("select title from agreedis where title = ? and sub = ?", [name, sub]) if(curs.fetchall()): curs.execute("insert into topic (id, title, sub, data, date, ip, block, top) values (?, ?, ?, '합의 결렬', ?, ?, '', '1')", [str(int(topic_check[0][0]) + 1), name, sub, time, ip]) curs.execute("delete from agreedis where title = ? and sub = ?", [name, sub]) else: curs.execute("insert into topic (id, title, sub, data, date, ip, block, top) values (?, ?, ?, '합의 완료', ?, ?, '', '1')", [str(int(topic_check[0][0]) + 1), name, sub, time, ip]) curs.execute("insert into agreedis (title, sub) values (?, ?)", [name, sub]) else: curs.execute("select title from stop where title = ? and sub = ? and close = ?", [name, sub, set_list[0]]) if(curs.fetchall()): curs.execute("insert into topic (id, title, sub, data, date, ip, block, top) values (?, ?, ?, ?, ?, ?, '', '1')", [str(int(topic_check[0][0]) + 1), name, sub, set_list[3], time, ip]) curs.execute("delete from stop where title = ? and sub = ? and close = ?", [name, sub, set_list[0]]) else: curs.execute("insert into topic (id, title, sub, data, date, ip, block, top) values (?, ?, ?, ?, ?, ?, '', '1')", [str(int(topic_check[0][0]) + 1), name, sub, set_list[2], time, ip]) curs.execute("insert into stop (title, sub, close) values (?, ?, ?)", [name, sub, set_list[0]]) curs.execute("delete from stop where title = ? and sub = ? and close = ?", [name, sub, set_list[1]]) rd_plus(conn, name, sub, time) conn.commit() return(redirect('/topic/' + url_pas(name) + '/sub/' + url_pas(sub))) @route('/topic//sub//admin/') def topic_admin(name = None, sub = None, num = None): curs.execute("select block, ip, date from topic where title = ? and sub = ? and id = ?", [name, sub, str(num)]) data = curs.fetchall() if(not data): return(redirect('/topic/' + url_pas(name) + '/sub/' + url_pas(sub))) ban = '' if(admin_check(conn, 3, None) == 1): ban += '== 관리 도구 ==\r\n' is_ban = ' * [[wiki:topic/' + url_pas(name) + '/sub/' + url_pas(sub) + '/b/' + str(num) + '|' if(data[0][0] == 'O'): is_ban += '가림 해제' else: is_ban += '가림' is_ban += ']]\r\n' curs.execute("select id from topic where title = ? and sub = ? and id = ? and top = 'O'", [name, sub, str(num)]) is_ban += ' * [[wiki:topic/' + url_pas(name) + '/sub/' + url_pas(sub) + '/notice/' + str(num) + '|' if(curs.fetchall()): is_ban += '공지 해제' else: is_ban += '공지' is_ban += ']]\r\n' curs.execute("select end from ban where block = ?", [data[0][1]]) ban += ' * [[wiki:/ban/' + url_pas(data[0][1]) + '|' if(curs.fetchall()): ban += '차단 해제' else: ban += '차단' ban += ']]\r\n' + is_ban ban += '== 기타 도구 ==\r\n' ban += ' * [[wiki:/topic/' + url_pas(name) + '/sub/' + url_pas(sub) + '/raw/' + str(num) + '|원본]]\r\n' ban = ' * 작성 시간 : ' + data[0][2] + '\r\n' + ban if(re.search('(\.|:)', data[0][1])): ban = ' * 작성인 : ' + data[0][1] + ' [[wiki:record/' + url_pas(data[0][1]) + '|(기록)]]\r\n' + ban else: ban = ' * 작성인 : [[사용자:' + data[0][1] + '|' + data[0][1] + ']] [[wiki:record/' + url_pas(data[0][1]) + '|(기록)]]\r\n' + ban ban = '== 정보 ==\r\n' + ban ban = '[목차(없음)]\r\n' + ban return(html_minify(template('index', imp = ['토론 도구', wiki_set(conn, 1), custom(conn), other2([' (' + str(num) + '번)', 0])], data = namumark(conn, '', ban, 0, 0, 0), menu = [['topic/' + url_pas(name) + '/sub/' + url_pas(sub) + '#' + str(num), '토론']] ))) @route('/topic//sub/', method=['POST', 'GET']) def topic(name = None, sub = None): ban = topic_check(conn, name, sub) admin = admin_check(conn, 3, None) if(request.method == 'POST'): if(captcha_post(request.forms.get('g-recaptcha-response'), conn) == 1): return(re_error(conn, '/error/13')) else: captcha_post('', conn, 0) ip = ip_check() today = get_time() if(ban == 1 and admin != 1): return(re_error(conn, '/ban')) curs.execute("select id from topic where title = ? and sub = ? order by id + 0 desc limit 1", [name, sub]) old_num = curs.fetchall() if(old_num): num = int(old_num[0][0]) + 1 else: num = 1 match = re.search('^사용자:([^/]+)', name) if(match): curs.execute('insert into alarm (name, data, date) values (?, ?, ?)', [match.groups()[0], ip + '님이 사용자 토론을 시작했습니다.', today]) data = re.sub("\[\[(분류:(?:(?:(?!\]\]).)*))\]\]", "[br]", request.forms.content) match = re.findall("(?:#([0-9]+))", data) for rd_data in match: curs.execute("select ip from topic where title = ? and sub = ? and id = ?", [name, sub, rd_data]) ip_data = curs.fetchall() if(ip_data and not re.search('(\.|:)', ip_data[0][0])): curs.execute('insert into alarm (name, data, date) values (?, ?, ?)', [ip_data[0][0], ip + '님이 토론에서 언급 했습니다.', today]) data = re.sub("(?P#(?:[0-9]+))", '[[\g]]', data) data = savemark(data) rd_plus(conn, name, sub, today) curs.execute("insert into topic (id, title, sub, data, date, ip, block, top) values (?, ?, ?, ?, ?, ?, '', '')", [str(num), name, sub, data, today, ip]) conn.commit() return(redirect('/topic/' + url_pas(name) + '/sub/' + url_pas(sub))) else: curs.execute("select title from stop where title = ? and sub = ? and close = 'O'", [name, sub]) close_data = curs.fetchall() curs.execute("select title from stop where title = ? and sub = ? and close = ''", [name, sub]) stop_data = curs.fetchall() curs.execute("select id from topic where title = ? and sub = ? limit 1", [name, sub]) topic_exist = curs.fetchall() display = '' all_data = '' data = '' number = 1 if(admin == 1 and topic_exist): if(close_data): all_data += '(열기) ' else: all_data += '(닫기) ' if(stop_data): all_data += '(재개) ' else: all_data += '(정지) ' curs.execute("select title from agreedis where title = ? and sub = ?", [name, sub]) if(curs.fetchall()): all_data += '(취소)' else: all_data += '(합의)' all_data += '
      ' if((close_data or stop_data) and admin != 1): display = 'display: none;' curs.execute("select data, id, date, ip, block, top from topic where title = ? and sub = ? order by id + 0 asc", [name, sub]) topic_1 = curs.fetchall() curs.execute("select data, id, date, ip from topic where title = ? and sub = ? and top = 'O' order by id + 0 asc", [name, sub]) topic_2 = curs.fetchall() for topic_data in topic_2: who_plus = '' curs.execute("select who from re_admin where what = ? order by time desc limit 1", ['notice (' + name + ' - ' + sub + '#' + topic_data[1] + ')']) topic_data_top = curs.fetchall() if(topic_data_top): who_plus += ' @' + topic_data_top[0][0] all_data += '
      ' all_data += '#' + topic_data[1] + ' ' + ip_pas(conn, topic_data[3]) + who_plus + ' ' + topic_data[2] + '' all_data += '
      ' + namumark(conn, '', topic_data[0], 0, 0, 0) + '

      ' for topic_data in topic_1: if(number == 1): start = topic_data[3] if(topic_data[4] == 'O'): blind_data = 'style="background: gainsboro;"' if(admin != 1): curs.execute("select who from re_admin where what = ? order by time desc limit 1", ['blind (' + name + ' - ' + sub + '#' + str(number) + ')']) who_blind = curs.fetchall() if(who_blind): user_write = '[[사용자:' + who_blind[0][0] + ']]님이 가림' else: user_write = '관리자가 가림' else: blind_data = '' user_write = namumark(conn, '', topic_data[0], 0, 0, 0) ip = ip_pas(conn, topic_data[3]) curs.execute('select acl from user where id = ?', [topic_data[3]]) user_acl = curs.fetchall() if(user_acl and user_acl[0][0] != 'user'): ip += ' ' if(admin == 1 or blind_data == ''): ip += ' (도구)' curs.execute("select end from ban where block = ?", [topic_data[3]]) if(curs.fetchall()): ip += ' ' if(topic_data[5] == '1'): color = '_blue' elif(topic_data[3] == start): color = '_green' else: color = '' if(user_write == ''): user_write = '
      ' all_data += '
      ' all_data += '#' + str(number) + ' ' + ip + '' all_data += '
      ' + user_write + '

      ' number += 1 custom_data = custom(conn) captcha = captcha_get(conn) if(ban != 1 or admin == 1): data += '' data += '


      ' + captcha if(custom_data[2] == 0 and display == ''): data += '비 로그인 상태입니다. 비 로그인으로 진행 시 아이피가 토론에 기록됩니다.
      ' data += '
      ' return(html_minify(template('index', imp = [name, wiki_set(conn, 1), custom_data, other2([' (토론)', 0])], data = '

      ' + sub + '

      ' + all_data + data, menu = [['topic/' + url_pas(name), '목록']] ))) @route('/topic/', method=['POST', 'GET']) @route('/topic//', method=['GET']) def close_topic_list(name = None, tool = None): div = '' list_d = 0 if(request.method == 'POST'): t_num = '' while(1): curs.execute("select title from topic where title = ? and sub = ? limit 1", [name, request.forms.topic + t_num]) if(curs.fetchall()): if(t_num == ''): t_num = ' 2' else: t_num = ' ' + str(int(t_num.replace(' ', '')) + 1) else: break return(redirect('/topic/' + url_pas(name) + '/sub/' + url_pas(request.forms.topic + t_num))) else: plus = '' menu = [['topic/' + url_pas(name), '목록']] if(tool == 'close'): curs.execute("select sub from stop where title = ? and close = 'O' order by sub asc", [name]) sub = '닫힘' elif(tool == 'agree'): curs.execute("select sub from agreedis where title = ? order by sub asc", [name]) sub = '합의' else: curs.execute("select sub from rd where title = ? order by date desc", [name]) sub = '토론 목록' menu = [['w/' + url_pas(name), '문서']] plus = '(닫힘) (합의)
      \
      \ ' for data in curs.fetchall(): curs.execute("select data, date, ip, block from topic where title = ? and sub = ? and id = '1'", [name, data[0]]) if(curs.fetchall()): it_p = 0 if(sub == '토론 목록'): curs.execute("select title from stop where title = ? and sub = ? and close = 'O' order by sub asc", [name, data[0]]) close = curs.fetchall() if(close): it_p = 1 if(it_p != 1): div += '

      ' + data[0] + '

      ' if(div == ''): plus = re.sub('^
      ', '', plus) return(html_minify(template('index', imp = [name, wiki_set(conn, 1), custom(conn), other2([' (' + sub + ')', 0])], data = '
      ' + div + plus + '
      ', menu = menu ))) @route('/login', method=['POST', 'GET']) def login(): session = request.environ.get('beaker.session') agent = request.environ.get('HTTP_USER_AGENT') if(session.get('Now') == 1): return(re_error(conn, '/error/11')) ip = ip_check() curs.execute("select ip from ok_login where ip = ?", [ip]) if(not curs.fetchall()): ban = ban_check(conn) else: ban = 0 if(ban == 1): return(re_error(conn, '/ban')) if(session.get('Now') == 1): return(re_error(conn, '/error/11')) if(request.method == 'POST'): if(captcha_post(request.forms.get('g-recaptcha-response'), conn) == 1): return(re_error(conn, '/error/13')) else: captcha_post('', conn, 0) curs.execute("select pw from user where id = ?", [request.forms.id]) user = curs.fetchall() if(not user): return(re_error(conn, '/error/5')) if(not bcrypt.checkpw(bytes(request.forms.pw, 'utf-8'), bytes(user[0][0], 'utf-8'))): return(re_error(conn, '/error/10')) session['Now'] = 1 session['DREAMER'] = request.forms.id curs.execute("select css from custom where user = ?", [request.forms.id]) css_data = curs.fetchall() if(css_data): session['Daydream'] = css_data[0][0] else: session['Daydream'] = '' curs.execute("insert into ua_d (name, ip, ua, today, sub) values (?, ?, ?, ?, '')", [request.forms.id, ip, agent, get_time()]) conn.commit() return(redirect('/user')) else: captcha = captcha_get(conn) return(html_minify(template('index', imp = ['로그인', wiki_set(conn, 1), custom(conn), other2([0, 0])], data = '
      \
      \
      \ ' + captcha + ' \
      \ 주의 : 만약 HTTPS 연결이 아닌 경우 데이터가 유출될 가능성이 있습니다. 이에 대해 책임지지 않습니다. \
      ', menu = [['user', '사용자']] ))) @route('/change', method=['POST', 'GET']) def change_password(): session = request.environ.get('beaker.session') ip = ip_check() ban = ban_check(conn) if(request.method == 'POST'): if(request.forms.pw2 != request.forms.pw3): return(re_error(conn, '/error/20')) if(ban == 1): return(re_error(conn, '/ban')) curs.execute("select pw from user where id = ?", [session['DREAMER']]) user = curs.fetchall() if(not user): return(re_error(conn, '/error/10')) if(re.search('(\.|:)', ip)): return(redirect('/login')) if(not bcrypt.checkpw(bytes(request.forms.pw, 'utf-8'), bytes(user[0][0], 'utf-8'))): return(re_error(conn, '/error/5')) hashed = bcrypt.hashpw(bytes(request.forms.pw2, 'utf-8'), bcrypt.gensalt()) curs.execute("update user set pw = ? where id = ?", [hashed.decode(), session['DREAMER']]) conn.commit() return(redirect('/user')) else: if(ban == 1): return(re_error(conn, '/ban')) if(re.search('(\.|:)', ip)): return(redirect('/login')) return(html_minify(template('index', imp = ['비밀번호 변경', wiki_set(conn, 1), custom(conn), other2([0, 0])], data = '
      \
      \
      \
      \
      \ 주의 : 만약 HTTPS 연결이 아닌 경우 데이터가 유출될 가능성이 있습니다. 이에 대해 책임지지 않습니다. \
      ', menu = [['user', '사용자']] ))) @route('/check/') @route('/check//') def user_check(name = None, name2 = None): curs.execute("select acl from user where id = ? or id = ?", [name, name2]) user = curs.fetchall() if(user and user[0][0] != 'user'): if(admin_check(conn, None, None) != 1): return(re_error(conn, '/error/4')) if(admin_check(conn, 4, 'check (' + name + ')') != 1): return(re_error(conn, '/error/3')) if(name2): if(re.search('(?:\.|:)', name)): if(re.search('(?:\.|:)', name2)): curs.execute("select name, ip, ua, today from ua_d where ip = ? or ip = ? order by today desc", [name, name2]) else: curs.execute("select name, ip, ua, today from ua_d where ip = ? or name = ? order by today desc", [name, name2]) else: if(re.search('(?:\.|:)', name2)): curs.execute("select name, ip, ua, today from ua_d where name = ? or ip = ? order by today desc", [name, name2]) else: curs.execute("select name, ip, ua, today from ua_d where name = ? or name = ? order by today desc", [name, name2]) elif(re.search('(?:\.|:)', name)): curs.execute("select name, ip, ua, today from ua_d where ip = ? order by today desc", [name]) else: curs.execute("select name, ip, ua, today from ua_d where name = ? order by today desc", [name]) record = curs.fetchall() if(record): div = '' div = '' for data in record: if(data[2]): ua = data[2] else: ua = '
      ' div += '' div += '' div += '
      이름아이피언제
      ' + ip_pas(conn, data[0]) + '' + ip_pas(conn, data[1]) + '' + data[3] + '
      ' + ua + '
      ' else: div = '' return(html_minify(template('index', imp = ['다중 검사', wiki_set(conn, 1), custom(conn), other2([0, 0])], data = div, menu = [['manager', '관리자']] ))) @route('/register', method=['POST', 'GET']) def register(): ip = ip_check() ban = ban_check(conn) if(ban == 1): return(re_error(conn, '/ban')) if(not admin_check(conn, None, None) == 1): curs.execute('select data from other where name = "reg"') set_d = curs.fetchall() if(set_d and set_d[0][0] == 'on'): return(re_error(conn, '/ban')) if(request.method == 'POST'): if(captcha_post(request.forms.get('g-recaptcha-response'), conn) == 1): return(re_error(conn, '/error/13')) else: captcha_post('', conn, 0) if(request.forms.pw != request.forms.pw2): return(re_error(conn, '/error/20')) if(re.search('(?:[^A-Za-zㄱ-힣0-9 ])', request.forms.id)): return(re_error(conn, '/error/8')) if(len(request.forms.id) > 32): return(re_error(conn, '/error/7')) curs.execute("select id from user where id = ?", [request.forms.id]) if(curs.fetchall()): return(re_error(conn, '/error/6')) hashed = bcrypt.hashpw(bytes(request.forms.pw, 'utf-8'), bcrypt.gensalt()) curs.execute("select id from user limit 1") user_ex = curs.fetchall() if(not user_ex): curs.execute("insert into user (id, pw, acl) values (?, ?, '소유자')", [request.forms.id, hashed.decode()]) else: curs.execute("insert into user (id, pw, acl) values (?, ?, 'user')", [request.forms.id, hashed.decode()]) conn.commit() return(redirect('/login')) else: contract = '' curs.execute('select data from other where name = "contract"') data = curs.fetchall() if(data and data[0][0] != ''): contract = data[0][0] + '
      ' captcha = captcha_get(conn) return(html_minify(template('index', imp = ['회원가입', wiki_set(conn, 1), custom(conn), other2([0, 0])], data = '
      \ ' + contract + ' \
      \
      \
      \ ' + captcha + ' \
      \ 주의 : 만약 HTTPS 연결이 아닌 경우 데이터가 유출될 가능성이 있습니다. 이에 대해 책임지지 않습니다. \
      ', menu = [['user', '사용자']] ))) @route('/logout') def logout(): session = request.environ.get('beaker.session') session['Now'] = 0 session.pop('DREAMER', None) return(redirect('/user')) @route('/ban/', method=['POST', 'GET']) def user_ban(name = None): curs.execute("select acl from user where id = ?", [name]) user = curs.fetchall() if(user and user[0][0] != 'user'): if(admin_check(conn, None, None) != 1): return(re_error(conn, '/error/4')) if(request.method == 'POST'): if(admin_check(conn, 1, 'ban (' + name + ')') != 1): return(re_error(conn, '/error/3')) ip = ip_check() time = get_time() time_list = [request.forms.month, request.forms.day, request.forms.hour, request.forms.minu] num = 0 for time_fix in time_list: if(not re.search("[0-9]{2}", time_fix)): time_list[num] = '0' + time_fix num += 1 if(request.forms.year == '09'): end = '' else: end = request.forms.year + '-' + time_list[0] + '-' + time_list[1] + ' ' + time_list[2] + ':' + time_list[3] + ':00' curs.execute("select block from ban where block = ?", [name]) if(curs.fetchall()): rb_plus(conn, name, '해제', time, ip, '') curs.execute("delete from ban where block = ?", [name]) else: if(re.search("^([0-9]{1,3}\.[0-9]{1,3})$", name)): band_d = 'O' else: band_d = '' rb_plus(conn, name, end, time, ip, request.forms.why) curs.execute("insert into ban (block, end, why, band) values (?, ?, ?, ?)", [name, end, request.forms.why, band_d]) if(request.forms.login_ok != ''): curs.execute("insert into ok_login (ip, sub) values (?, '')", [name]) conn.commit() return(redirect('/ban/' + url_pas(name))) else: if(admin_check(conn, 1, None) != 1): return(re_error(conn, '/error/3')) curs.execute("select end from ban where block = ?", [name]) end = curs.fetchall() if(end): now = '차단 해제' if(end[0][0] == ''): data = '영구 차단
      ' else: data = end[0][0] + ' 까지 차단
      ' else: if(re.search("^([0-9]{1,3}\.[0-9]{1,3})$", name)): now = '대역 차단' else: now = '차단' now_time = get_time() m = re.search('^([0-9]{4})-([0-9]{2})-([0-9]{2}) ([0-9]{2}):([0-9]{2}):[0-9]{2}', now_time) g = m.groups() year = '' for i in range(int(g[0]), int(g[0]) + 11): if(i == int(g[0])): year += '' else: year += '' month = '' for i in range(1, 13): if(i == int(g[1])): month += '' else: month += '' day = '' for i in range(1, 32): if(i == int(g[2])): day += '' else: day += '' hour = '' for i in range(0, 24): if(i == int(g[3])): hour += '' else: hour += '' minu = '' for i in range(0, 61): if(i == int(g[4])): minu += '' else: minu += '' is_it = '' if(re.search('(\.|:)', name)): plus = ' 로그인 가능
      ' else: plus = '' data = ' 년 ' data += ' 월 ' data += '
      ' data += ' 시 ' data += ' 분 까지
      ' data += '
      ' + plus return(html_minify(template('index', imp = [name, wiki_set(conn, 1), custom(conn), other2([' (' + now + ')', 0])], data = '
      ' + data + '
      ', menu = [['manager', '관리자']] ))) @route('/user_acl/', method=['POST', 'GET']) def acl(name = None): ip = ip_check() if(ip != name or re.search("(\.|:)", name)): return(redirect('/login')) if(request.method == 'POST'): curs.execute("select acl from data where title = ?", ['사용자:' + name]) acl_d = curs.fetchall() if(acl_d): if(request.forms.select == 'all'): curs.execute("update data set acl = 'all' where title = ?", ['사용자:' + name]) elif(request.forms.select == 'user'): curs.execute("update data set acl = 'user' where title = ?", ['사용자:' + name]) else: curs.execute("update data set acl = '' where title = ?", ['사용자:' + name]) conn.commit() return(redirect('/w/' + url_pas('사용자:' + name))) curs.execute("select acl from data where title = ?", ['사용자:' + name]) acl_d = curs.fetchall() if(acl_d): if(acl_d[0][0] == 'all'): now = '모두' elif(acl_d[0][0] == 'user'): now = '가입자' else: now = '일반' return(html_minify(template('index', imp = [name, wiki_set(conn, 1), custom(conn), other2([' (사문 ACL)', 0])], data = '현재 ACL : ' + now + '
      \
      \
      \ \
      ', menu = [['user', '사용자']] ))) else: return(redirect('/w/' + url_pas(name))) @route('/acl/', method=['POST', 'GET']) def acl(name = None): if(request.method == 'POST'): if(admin_check(conn, 5, 'acl (' + name + ')') != 1): return(re_error(conn, '/error/3')) curs.execute("select acl from data where title = ?", [name]) if(curs.fetchall()): if(request.forms.select == 'admin'): acl = 'admin' elif(request.forms.select == 'user'): acl = 'user' else: acl = '' curs.execute("update data set acl = ? where title = ?", [acl, name]) conn.commit() return(redirect('/w/' + url_pas(name))) else: if(admin_check(conn, 5, None) != 1): return(re_error(conn, '/error/3')) curs.execute("select acl from data where title = ?", [name]) acl = curs.fetchall() if(acl): if(acl[0][0] == 'admin'): now = '관리자' elif(acl[0][0] == 'user'): now = '가입자' else: now = '일반' return(html_minify(template('index', imp = [name, wiki_set(conn, 1), custom(conn), other2([' (ACL)', 0])], data = '현재 ACL : ' + now + '
      \
      \
      \ \
      ', menu = [['w/' + url_pas(name), '문서'], ['manager', '관리자']] ))) else: return(redirect('/w/' + url_pas(name))) @route('/admin/', method=['POST', 'GET']) def user_admin(name = None): owner = admin_check(conn, None, None) curs.execute("select acl from user where id = ?", [name]) user = curs.fetchall() if(not user): return(re_error(conn, '/error/5')) else: if(owner != 1): curs.execute('select name from alist where name = ? and acl = "owner"', [user[0][0]]) if(curs.fetchall()): return(re_error(conn, '/error/3')) if(ip_check() == name): return(re_error(conn, '/error/3')) if(request.method == 'POST'): if(admin_check(conn, 7, 'admin (' + name + ')') != 1): return(re_error(conn, '/error/3')) curs.execute('select name from alist where name = ? and acl = "owner"', [request.forms.select]) if(curs.fetchall()): return(re_error(conn, '/error/3')) if(request.forms.select == 'X'): curs.execute("update user set acl = 'user' where id = ?", [name]) else: curs.execute("update user set acl = ? where id = ?", [request.forms.select, name]) conn.commit() return(redirect('/admin/' + url_pas(name))) else: if(admin_check(conn, 7, None) != 1): return(re_error(conn, '/error/3')) div = '' curs.execute('select distinct name from alist order by name asc') get_alist = curs.fetchall() if(get_alist): i = 0 name_rem = '' for data in get_alist: if(user[0][0] == data[0]): div += '' else: if(owner != 1): curs.execute('select name from alist where name = ? and acl = "owner"', [data[0]]) if(not curs.fetchall()): div += '' else: div += '' return(html_minify(template('index', imp = [name, wiki_set(conn, 1), custom(conn), other2([' (권한 부여)', 0])], data = '
      \
      \ \
      ', menu = [['manager', '관리자']] ))) @route('/w//r//diff/') def diff_data(name = None, first = None, second = None): curs.execute("select data from history where id = ? and title = ?", [str(first), name]) first_raw_data = curs.fetchall() if(first_raw_data): curs.execute("select data from history where id = ? and title = ?", [str(second), name]) second_raw_data = curs.fetchall() if(second_raw_data): first_data = html.escape(first_raw_data[0][0]) second_data = html.escape(second_raw_data[0][0]) if(first == second): result = '내용이 같습니다.' else: diff_data = difflib.SequenceMatcher(None, first_data, second_data) result = diff(diff_data) return(html_minify(template('index', imp = [name, wiki_set(conn, 1), custom(conn), other2([' (비교)', 0])], data = '
      ' + result + '
      ', menu = [['history/' + url_pas(name), '역사']] ))) return(redirect('/history/' + url_pas(name))) @route('/down/') def down(name = None): curs.execute("select title from data where title like ?", ['%' + name + '/%']) under = curs.fetchall() div = '' return(html_minify(template('index', imp = [name, wiki_set(conn, 1), custom(conn), other2([' (하위)', 0])], data = div, menu = [['w/' + url_pas(name), '문서']] ))) @route('/w/') @route('/w//r/') @route('/w//from/') def read_view(name = None, num = None, redirect = None): data_none = 0 sub = '' acl = '' div = '' topic = 0 if(not num): session = request.environ.get('beaker.session') if(session.get('View_List')): m = re.findall('([^\n]+)\n', session.get('View_List')) if(m[-1] != name): d = re.sub(name + '\n', '', session.get('View_List')) d += name + '\n' if(len(m) > 50): d = re.sub('([^\n]+)\n', '', d, 1) session['View_List'] = d else: session['View_List'] = name + '\n' curs.execute("select sub from rd where title = ? order by date desc", [name]) rd = curs.fetchall() for data in rd: curs.execute("select title from stop where title = ? and sub = ? and close = 'O'", [name, data[0]]) if(not curs.fetchall()): topic = 1 break curs.execute("select title from data where title like ?", ['%' + name + '/%']) if(curs.fetchall()): down = 1 else: down = 0 m = re.search("^(.*)\/(.*)$", name) if(m): uppage = m.groups()[0] else: uppage = 0 if(admin_check(conn, 5, None) == 1): admin_memu = 1 else: admin_memu = 0 if(re.search("^분류:", name)): curs.execute("select link from back where title = ? and type='cat' order by link asc", [name]) back = curs.fetchall() if(back): div = '[목차(없음)]\r\n== 분류 ==\r\n' u_div = '' i = 0 for data in back: if(re.search('^분류:', data[0])): if(u_div == ''): u_div = '=== 하위 분류 ===\r\n' u_div += ' * [[:' + data[0] + ']]\r\n' elif(re.search('^틀:', data[0])): curs.execute("select data from data where title = ?", [data[0]]) db_data = curs.fetchall() if(db_data): if(re.search('\[\[' + name + ']]', mid_pas(db_data[0][0], 0, 1, 0)[0])): div += ' * [[' + data[0] + ']]\r\n * [[wiki:xref/' + url_pas(data[0]) + '|' + data[0] + ']] (역링크)\r\n' else: div += ' * [[' + data[0] + ']]\r\n' else: div += ' * [[' + data[0] + ']]\r\n' div += u_div if(num): curs.execute("select title from history where title = ? and id = ? and hide = 'O'", [name, str(num)]) hid = curs.fetchall() if(hid and admin_check(conn, 6, None) != 1): return(redirect('/history/' + url_pas(name))) curs.execute("select title, data from history where title = ? and id = ?", [name, str(num)]) else: curs.execute("select acl, data from data where title = ?", [name]) data = curs.fetchall() if(data): if(not num): if(data[0][0] == 'admin'): acl = ' (관리자)' elif(data[0][0] == 'user'): acl = ' (가입자)' else: curs.execute('select data from other where name = "edit"') set_data = curs.fetchall() if(set_data): if(set_data[0][0] == 'admin'): acl = ' (관리자)' elif(set_data[0][0] == 'user'): acl = ' (가입자)' elsedata = data[0][1] else: curs.execute('select data from other where name = "edit"') set_data = curs.fetchall() if(set_data): if(set_data[0][0] == 'admin'): acl = ' (관리자)' elif(set_data[0][0] == 'user'): acl = ' (가입자)' data_none = 1 response.status = 404 elsedata = '' m = re.search("^사용자:([^/]*)", name) if(m): g = m.groups() curs.execute("select acl from user where id = ?", [g[0]]) test = curs.fetchall() if(test and test[0][0] != 'user'): acl = ' (관리자)' else: acl = '' if(data): if(data[0][0] == 'all'): acl += ' (모두)' elif(data[0][0] == 'user'): acl += ' (가입자)' curs.execute("select block from ban where block = ?", [g[0]]) user = curs.fetchall() if(user): sub = ' (차단)' if(redirect): elsedata = re.sub("^#(?:redirect|넘겨주기) (?P[^\n]*)", " * [[\g]] 문서로 넘겨주기", elsedata) enddata = namumark(conn, name, elsedata, 0, 0, 1) if(data_none == 1): menu = [['edit/' + url_pas(name), '생성'], ['topic/' + url_pas(name), topic], ['history/' + url_pas(name), '역사'], ['move/' + url_pas(name), '이동'], ['xref/' + url_pas(name), '역링크']] else: menu = [['edit/' + url_pas(name), '수정'], ['topic/' + url_pas(name), topic], ['history/' + url_pas(name), '역사'], ['delete/' + url_pas(name), '삭제'], ['move/' + url_pas(name), '이동'], ['raw/' + url_pas(name), '원본'], ['xref/' + url_pas(name), '역링크']] if(admin_memu == 1): menu += [['acl/' + url_pas(name), 'ACL']] if(redirect): menu += [['w/' + url_pas(name), '넘기기']] enddata = '
      ' + enddata if(uppage != 0): menu += [['w/' + url_pas(uppage), '상위']] if(down): menu += [['down/' + url_pas(name), '하위']] if(num): menu = [['history/' + url_pas(name), '역사']] sub = ' (' + str(num) + '판)' acl = '' r_date = 0 else: curs.execute("select date from history where title = ? order by date desc limit 1", [name]) date = curs.fetchall() if(date): r_date = date[0][0] else: r_date = 0 if(div != '' and enddata != ''): div = enddata + '
      ' + namumark(conn, name, div, 0, 0, 0) else: div = enddata + namumark(conn, name, div, 0, 0, 0) return(html_minify(template('index', imp = [name, wiki_set(conn, 1), custom(conn), other2([sub + acl, r_date])], data = div, menu = menu ))) @route('/topic_record/') @route('/topic_record//') def user_topic_list(name = None, num = 1): if(num * 50 > 0): sql_num = num * 50 - 50 else: sql_num = 0 one_admin = admin_check(conn, 1, None) div = '' div += '' div = '(편집 기록)
      ' + div curs.execute("select title, id, sub, ip, date from topic where ip = ? order by date desc limit ?, '50'", [name, str(sql_num)]) for data in curs.fetchall(): title = html.escape(data[0]) sub = html.escape(data[2]) if(one_admin == 1): curs.execute("select * from ban where block = ?", [data[3]]) if(curs.fetchall()): ban = ' (해제)' else: ban = ' (차단)' else: ban = '' ip = ip_pas(conn, data[3]) div += '' div += '' div += '
      토론명작성자시간
      ' + title + '#' + data[1] + ' (' + sub + ')' + ip + ban + '' + data[4] + '
      ' div += '
      (이전) (이후)' curs.execute("select end, why from ban where block = ?", [name]) ban_it = curs.fetchall() if(ban_it): sub = ' (차단)' else: sub = 0 return(html_minify(template('index', imp = ['토론 기록', wiki_set(conn, 1), custom(conn), other2([sub, 0])], data = div, menu = [['other', '기타'], ['user', '사용자'], ['count/' + url_pas(name), '횟수']] ))) @route('//', method=['POST', 'GET']) @route('///num/', method=['POST', 'GET']) @route('/record///') @route('/recent_changes') @route('/recent_changes/') def recent_changes(name = None, num = 1, what = 'all', tool = 'record'): if(request.method == 'POST'): return(redirect('/w/' + url_pas(name) + '/r/' + request.forms.b + '/diff/' + request.forms.a)) else: one_admin = admin_check(conn, 1, None) six_admin = admin_check(conn, 6, None) ban = '' select = '' div = '' if(name): if(num * 50 > 0): sql_num = num * 50 - 50 else: sql_num = 0 if(tool == 'history'): div += '' curs.execute("select id, title, date, ip, send, leng from history where title = ? order by id + 0 desc limit ?, '50'", [name, str(sql_num)]) elif(tool == 'record'): div += '' if(what == 'all'): div = '(토론 기록)
      ' + div div = '(되돌리기) ' + div div = '(이동) ' + div div = '(삭제) ' + div curs.execute("select id, title, date, ip, send, leng from history where ip = ? order by date desc limit ?, '50'", [name, str(sql_num)]) else: if(what == 'delete'): sql = '%(삭제)' elif(what == 'move'): sql = '%이동)' elif(what == 'revert'): sql = '%판)' else: return(redirect('/')) curs.execute("select id, title, date, ip, send, leng from history where ip = ? and send like ? order by date desc limit ?, '50'", [name, sql, str(sql_num)]) else: return(redirect('/')) else: div += '' if(what == 'all'): div = '(되돌리기)
      ' + div div = '(이동) ' + div div = '(삭제) ' + div curs.execute("select id, title, date, ip, send, leng from history order by date desc limit 50") else: if(what == 'delete'): sql = '%(삭제)' elif(what == 'move'): sql = '%이동)' elif(what == 'revert'): sql = '%판)' else: return(redirect('/')) curs.execute("select id, title, date, ip, send, leng from history where send like ? order by date desc limit 50", [sql]) for data in curs.fetchall(): select += '' send = '
      ' if(data[4]): if(not re.search("^(?: *)$", data[4])): send = data[4] if(re.search("\+", data[5])): leng = '' + data[5] + '' elif(re.search("\-", data[5])): leng = '' + data[5] + '' else: leng = '' + data[5] + '' if(one_admin == 1): curs.execute("select * from ban where block = ?", [data[3]]) if(curs.fetchall()): ban = ' (해제)' else: ban = ' (차단)' ip = ip_pas(conn, data[3]) if((int(data[0]) - 1) == 0): revert = '' else: revert = '(비교)(되돌리기)' style = ['', ''] date = data[2] curs.execute("select title from history where title = ? and id = ? and hide = 'O'", [data[1], data[0]]) hide = curs.fetchall() if(six_admin == 1): if(hide): hidden = ' (공개)' style[0] = 'background: gainsboro;' style[1] = 'background: gainsboro;' if(send == '
      '): send = '(숨김)' else: send += ' (숨김)' else: hidden = '
      (숨김)' elif(not hide): hidden = '' else: ip = '' hidden = '' ban = '' date = '' send = '(숨김)' style[0] = 'display: none;' style[1] = 'background: gainsboro;' if(tool == 'history'): title = '' + data[0] + '판(원본) ' else: title = '' + html.escape(data[1]) + ' (' + data[0] + '판) ' div += '' div += '' div += '
      편집자시간
      문서명편집자시간
      문서명편집자시간
      ' + title + revert + ' (' + leng + ')' + ip + ban + hidden + '' + date + '
      ' + send + '
      ' sub = '' if(name): if(tool == 'history'): div = '

      ' + div title = name sub += ' (역사)' menu = [['w/' + url_pas(name), '문서'], ['move_data/' + url_pas(name), '이동 기록']] div += '
      (이전) (이후)' else: curs.execute("select end, why from ban where block = ?", [name]) ban_it = curs.fetchall() if(ban_it): sub += ' (차단)' title = '편집 기록' menu = [['other', '기타'], ['user', '사용자'], ['count/' + url_pas(name), '횟수']] if(what): div += '
      (이전) (이후)' else: div += '
      (이전) (이후)' if(what != 'all'): menu += [['record/' + url_pas(name), '일반']] else: menu = 0 title = '최근 변경내역' if(what != 'all'): menu = [['recent_changes', '일반']] if(what == 'delete'): sub += ' (삭제)' elif(what == 'move'): sub += ' (이동)' elif(what == 'revert'): sub += ' (되돌리기)' if(sub == ''): sub = 0 return(html_minify(template('index', imp = [title, wiki_set(conn, 1), custom(conn), other2([sub, 0])], data = div, menu = menu ))) @route('/upload', method=['GET', 'POST']) def upload(): if(ban_check(conn) == 1): return(re_error(conn, '/ban')) if(request.method == 'POST'): if(captcha_post(request.forms.get('g-recaptcha-response'), conn) == 1): return(re_error(conn, '/error/13')) else: captcha_post('', conn, 0) data = request.files.get('f_data') if(not data): return(re_error(conn, '/error/9')) if(int(wiki_set(conn, 3)) * 1024 * 1024 < request.content_length): return(re_error(conn, '/error/17')) value = os.path.splitext(data.filename)[1] if(not value): return(re_error(conn, '/error/22')) if(not value in ['.jpeg', '.jpg', '.gif', '.png', '.webp', '.JPEG', '.JPG', '.GIF', '.PNG', '.WEBP']): return(re_error(conn, '/error/14')) if(request.forms.get('f_name')): name = request.forms.get('f_name') + value else: name = data.filename piece = os.path.splitext(name) e_data = sha224(piece[0]) + piece[1] ip = ip_check() if(request.forms.get('f_lice')): lice = request.forms.get('f_lice') else: if(re.search('(?:\.|:)', ip)): lice = ip + ' 올림' else: lice = '[[사용자:' + ip + ']] 올림' if(os.path.exists(os.path.join('image', e_data))): return(re_error(conn, '/error/16')) data.save(os.path.join('image', e_data)) curs.execute("select title from data where title = ?", ['파일:' + name]) exist = curs.fetchall() if(exist): curs.execute("delete from data where title = ?", ['파일:' + name]) curs.execute("insert into data (title, data, acl) values (?, ?, 'admin')", ['파일:' + name, '[[파일:' + name + ']][br][br]{{{[[파일:' + name + ']]}}}[br][br]' + lice]) history_plus(conn, '파일:' + name, '[[파일:' + name + ']][br][br]{{{[[파일:' + name + ']]}}}[br][br]' + lice, get_time(), ip, '(파일 올림)', '0') conn.commit() return(redirect('/w/파일:' + name)) else: captcha = captcha_get(conn) return(html_minify(template('index', imp = ['파일 올리기', wiki_set(conn, 1), custom(conn), other2([0, 0])], data = '
      \
      \
      \
      \ ' + captcha + ' \ \
      ', menu = [['other', '기타']] ))) @route('/user') def user_info(): ip = ip_check() curs.execute("select acl from user where id = ?", [ip]) data = curs.fetchall() if(ban_check(conn) == 0): if(data): if(data[0][0] != 'user'): acl = data[0][0] else: acl = '가입자' else: acl = '일반' else: acl = '차단' curs.execute("select ip from ok_login where ip = ?", [ip]) if(curs.fetchall()): acl += ' (로그인 가능)' if(not re.search('(\.|:)', ip)): ip_user = '[[사용자:' + ip + '|' + ip + ']]' else: ip_user = ip custom_data = custom(conn) if(custom_data[2] != 0): plus = ' * [[wiki:logout|로그아웃]]\r\n * [[wiki:change|비밀번호 변경]]' else: plus = ' * [[wiki:login|로그인]]' return(html_minify(template('index', imp = ['사용자 메뉴', wiki_set(conn, 1), custom_data, other2([0, 0])], data = namumark(conn, '', '[목차(없음)]\r\n' + \ '== 상태 ==\r\n' + \ ' * ' + ip_user + '\r\n' ' * 권한 상태 : ' + acl + '\r\n' + \ '== 로그인 ==\r\n' + \ plus + '\r\n' + \ ' * [[wiki:register|회원가입]]\r\n' + \ '== 사용자 기능 ==\r\n' + \ ' * [[wiki:user_acl/' + url_pas(ip) + '|사용자 문서 ACL]]\r\n' + \ ' * [[wiki:custom_head|사용자 HEAD]]\r\n' + \ '== 기타 ==\r\n' + \ ' * [[wiki:alarm|알림]]\r\n' + \ ' * [[wiki:view_log|지나온 문서]]\r\n' + \ ' * [[wiki:record/' + url_pas(ip) + '|편집 기록]]\r\n' + \ ' * [[wiki:topic_record/' + url_pas(ip) + '|토론 기록]]\r\n' + \ ' * [[wiki:count|활동 횟수]]\r\n', 0, 0, 0), menu = 0 ))) @route('/view_log') def view_log(): session = request.environ.get('beaker.session') data = '
        ' if(session.get('View_List')): data += '
      • 최근 50개

      • ' m = re.findall('([^\n]+)\n', session.get('View_List')) for d in m: data += '
      • ' + d + '
      • ' else: data += '
      • 기록 없음
      • ' data += '
      ' return(html_minify(template('index', imp = ['지나온 문서', wiki_set(conn, 1), custom(conn), other2([0, 0])], data = data, menu = [['user', '사용자']] ))) @route('/custom_head', method=['GET', 'POST']) def custom_head_view(): session = request.environ.get('beaker.session') ip = ip_check() if(request.method == 'POST'): if(not re.search('(\.|:)', ip)): curs.execute("select user from custom where user = ?", [ip + ' (head)']) if(curs.fetchall()): curs.execute("update custom set css = ? where user = ?", [request.forms.content, ip + ' (head)']) else: curs.execute("insert into custom (user, css) values (?, ?)", [ip + ' (head)', request.forms.content]) conn.commit() session['MyMaiToNight'] = request.forms.content return(redirect('/user')) else: if(not re.search('(\.|:)', ip)): start = '' curs.execute("select css from custom where user = ?", [ip + ' (head)']) head_data = curs.fetchall() if(head_data): data = head_data[0][0] else: data = '' else: start = '비 로그인의 경우에는 로그인하거나 브라우저 닫으면 날아갑니다.
      ' try: data = session['MyMaiToNight'] except: data = '' start += '<style>CSS</style>
      <script>JS</script>

      ' return(html_minify(template('index', imp = ['사용자 HEAD', wiki_set(conn, 1), custom(conn), other2([0, 0])], data = start + ' \
      \
      \ \
      ', menu = [['user', '사용자']] ))) @route('/count') @route('/count/') def count_edit(name = None): if(name == None): that = ip_check() else: that = name curs.execute("select count(title) from history where ip = ?", [that]) count = curs.fetchall() if(count): data = count[0][0] else: data = 0 curs.execute("select count(title) from topic where ip = ?", [that]) count = curs.fetchall() if(count): t_data = count[0][0] else: t_data = 0 return(html_minify(template('index', imp = ['활동 횟수', wiki_set(conn, 1), custom(conn), other2([0, 0])], data = namumark(conn, "", "[목차(없음)]\r\n== " + that + " ==\r\n||<:> 편집 횟수 ||<:> " + str(data) + "||\r\n||<:> 토론 횟수 ||<:> " + str(t_data) + "||", 0, 0, 0), menu = [['user', '사용자'], ['record/' + url_pas(that), '편집 기록'], ['topic_record/' + url_pas(that), '토론 기록']] ))) @route('/random') def random(): curs.execute("select title from data order by random() limit 1") d = curs.fetchall() if(d): return(redirect('/w/' + url_pas(d[0][0]))) else: return(redirect('/')) @route('/views/') def views(name = None): if(re.search('\/', name)): m = re.search('^(.*)\/(.*)$', name) if(m): n = m.groups() plus = '/' + n[0] rename = n[1] else: plus = '' rename = name else: plus = '' rename = name m = re.search('\.(.+)$', name) if(m): g = m.groups() else: g = [''] if(g == 'css'): return(css_minify(static_file(rename, root = './views' + plus))) elif(g == 'js'): return(js_minify(static_file(rename, root = './views' + plus))) elif(g == 'html'): return(html_minify(static_file(rename, root = './views' + plus))) else: return(static_file(rename, root = './views' + plus)) @route('/robots.txt') def random(): curs.execute("select data from other where name = 'robot'") d = curs.fetchall() if(d): return('
      ' + d[0][0] + '
      ') else: return('') @error(404) def error_404(error): try: curs.execute("select title from data limit 1") return('' + redirect('/w/' + url_pas(wiki_set(conn, 2)))) except: return('' + redirect('/setup')) @error(500) def error_500(error): try: curs.execute("select title from data limit 1") return('' + error) except: return('' + redirect('/setup')) run(app = app, server = 'tornado', host = '0.0.0.0', port = int(set_data['port']), debug = True)