Răsfoiți Sursa

Merge pull request #1778 from openNAMU/dev

Dev
잉여개발기 (SPDV) 3 ani în urmă
părinte
comite
dc02e55058

+ 34 - 61
app.py

@@ -3,26 +3,7 @@ import os
 import re
 
 from route.tool.func import *
-# from route import *
-
-for i_data in os.listdir("route"):
-    f_src = re.search(r"(.+)\.py$", i_data)
-    f_src = f_src.group(1) if f_src else ""
-    
-    if not f_src in ('', '__init__'):
-        try:
-            exec(
-                "from route." + f_src + " " + 
-                "import " + f_src
-            )
-        except:
-            try:
-                exec(
-                    "from route." + f_src + " " + 
-                    "import " + f_src + "_2"
-                )
-            except:
-                pass
+from route import *
 
 # Init-Version
 version_list = json.loads(open(
@@ -70,6 +51,8 @@ with get_db_connect() as conn:
             except:
                 pass
 
+        conn.select_db(data_db_set['name'])
+
     if setup_tool != 'normal':
         create_data = get_db_table_list()
         for create_table in create_data:
@@ -317,53 +300,37 @@ app.route('/list/document/old')(list_old_page)
 app.route('/list/document/old/<int:num>')(list_old_page)
 
 # /list/document/acl
-@app.route('/acl_list')
-def list_acl():
-    return list_acl_2()
-
-# /list/document/acl/add
-@app.route('/acl/<everything:name>', methods = ['POST', 'GET'])
-def give_acl(name = None):
-    return give_acl_2(name)
+app.route('/list/document/acl')(list_acl)
+app.route('/list/document/acl/<int:arg_num>')(list_acl)
 
 # /list/document/need
-@app.route('/please')
-def list_please():
-    return list_please_2()
+app.route('/list/document/need')(list_please)
+app.route('/list/document/need/<int:arg_num>')(list_please)
 
 # /list/document/all
 app.route('/list/document/all')(list_title_index)
 app.route('/list/document/all/<int:num>')(list_title_index)
 
 # /list/document/long
-@app.route('/long_page')
-def list_long_page():
-    return list_long_page_2('long_page')
+app.route('/list/document/long')(list_long_page)
 
 # /list/document/short
-@app.route('/short_page')
-def list_short_page():
-    return list_long_page_2('short_page')
+app.route('/list/document/short', defaults = { 'tool' : 'short_page' })(list_long_page)
 
 # /list/file
-@app.route('/image_file_list')
-def list_image_file():
-    return list_image_file_2()
+app.route('/list/file')(list_image_file)
 
 # /list/admin
 # /list/admin/list
-@app.route('/admin_list')
-def list_admin():
-    return list_admin_2()
+app.route('/list/admin')(list_admin)
 
 # /list/admin/auth_use
-app.route('/list/admin/auth_use', methods = ['POST', 'GET'])(list_admin_use)
-app.route('/list/admin/auth_use/<arg_search>/<int:arg_num>', methods = ['POST', 'GET'])(list_admin_use)
+app.route('/list/admin/auth_use', methods = ['POST', 'GET'])(list_admin_auth_use)
+app.route('/list/admin/auth_use/<arg_search>/<int:arg_num>', methods = ['POST', 'GET'])(list_admin_auth_use)
 
 # /list/user
-@app.route('/user_log')
-def list_user():
-    return list_user_2()
+app.route('/list/user')(list_user)
+app.route('/list/user/<int:arg_num>')(list_user)
 
 # /list/user/check
 @app.route('/check/<name>')
@@ -378,9 +345,8 @@ def give_user_check_delete():
 # Func-auth
 # /auth/give
 # /auth/give/<name>
-@app.route('/admin/<name>', methods = ['POST', 'GET'])
-def give_admin(name = None):
-    return give_admin_2(name)
+app.route('/auth/give', methods = ['POST', 'GET'])(give_auth)
+app.route('/auth/give/<name>', methods = ['POST', 'GET'])(give_auth)
 
 # /auth/give
 # /auth/give/<name>
@@ -447,6 +413,8 @@ app.route('/diff/<int(signed = True):num_a>/<int(signed = True):num_b>/<everythi
 
 app.route('/down/<everything:name>')(view_down)
 
+app.route('/acl/<everything:name>', methods = ['POST', 'GET'])(view_acl)
+
 # everything 다음에 추가 붙은 경우에 대해서 재검토 필요 (진행중)
 app.route('/w_rev/<int(signed = True):doc_rev>/<everything:name>')(view_read)
 app.route('/w_from/<everything:name>', defaults = { 'do_type' : 'from' })(view_read)
@@ -589,13 +557,17 @@ app.route('/vote/list/close/<int:num>', defaults = { 'list_type' : 'close' })(vo
 app.route('/vote/add', methods = ['POST', 'GET'])(vote_add)
 
 # Func-bbs
-# app.route('/bbs/main')
+app.route('/bbs/main')(bbs_main)
+app.route('/bbs/make', methods = ['POST', 'GET'])(bbs_make)
 # app.route('/bbs/main/set')
-# app.route('/bbs/make')
-# app.route('/bbs/w/<int:bbs_num>')
-# app.route('/bbs/set/<int:bbs_num>')
-# app.route('/bbs/edit/<int:bbs_num>')
-# app.route('/bbs/w/<int:bbs_num>/<int:post_num>')
+app.route('/bbs/w/<int:bbs_num>')(bbs_w)
+app.route('/bbs/set/<int:bbs_num>', methods = ['POST', 'GET'])(bbs_w_set)
+app.route('/bbs/edit/<int:bbs_num>', methods = ['POST', 'GET'])(bbs_edit)
+app.route('/bbs/edit/preview/<int:bbs_num>', methods = ['POST', 'GET'], defaults = { 'do_type' : 'preview' })(bbs_edit)
+app.route('/bbs/w/<int:bbs_num>/<int:post_num>', methods = ['POST', 'GET'])(bbs_w_post)
+app.route('/bbs/edit/<int:bbs_num>/<int:post_num>', methods = ['POST', 'GET'])(bbs_edit)
+app.route('/bbs/edit/preview/<int:bbs_num>/<int:post_num>', methods = ['POST', 'GET'], defaults = { 'do_type' : 'preview' })(bbs_edit)
+app.route('/bbs/w/preview/<int:bbs_num>/<int:post_num>', methods = ['POST'], defaults = { 'do_type' : 'preview' })(bbs_w_post)
 # app.route('/bbs/edit/<int:bbs_num>/<int:post_num>')
 
 # Func-api
@@ -610,6 +582,7 @@ app.route('/api/skin_info/<name>')(api_skin_info)
 app.route('/api/user_info/<name>', methods = ['POST', 'GET'])(api_user_info)
 app.route('/api/setting/<name>')(api_setting)
 
+app.route('/api/thread/<int:topic_num>/<tool>/<int:num>/<render>')(api_topic)
 app.route('/api/thread/<int:topic_num>/<tool>/<int:num>')(api_topic)
 app.route('/api/thread/<int:topic_num>/<tool>')(api_topic)
 app.route('/api/thread/<int:topic_num>')(api_topic)
@@ -668,9 +641,9 @@ app.route('/setting/skin_set', methods = ['POST', 'GET'])(main_setting_skin_set)
 app.route('/easter_egg')(main_func_easter_egg)
 
 # views -> view
-app.route('/view/<everything:name>')(main_view)
-app.route('/views/<everything:name>')(main_view)
-app.route('/image/<everything:name>')(main_view_image)
+app.route('/view/<path:name>')(main_view)
+app.route('/views/<path:name>')(main_view)
+app.route('/image/<path:name>')(main_view_image)
 # 조정 계획 중
 app.route('/<regex("[^.]+\.(?:txt|xml)"):data>')(main_view_file)
 
@@ -686,4 +659,4 @@ if __name__ == "__main__":
         host = server_set['host'],
         port = int(server_set['port']),
         threads = 1
-    )
+    )

+ 4 - 2
emergency_tool.py

@@ -239,14 +239,16 @@ elif what_i_do == '20':
     print('----')
     domain = input('Domain (EX : 2du.pythonanywhere.com) : ')
 
-    curs.execute(db_change("update other set data = ? where name = 'domain'"), [domain])
+    curs.execute(db_change('delete from other where name = "domain"'))
+    curs.execute(db_change('insert into other (name, data, coverage) values ("domain", ?, "")'), [domain])
 elif what_i_do == '21':
     print('----')
     tls_v = input('TLS (http) [http, https] : ')
     if not tls_v in ['http', 'https']:
         tls_v = 'http'
 
-    curs.execute(db_change("update other set data = ? where name = 'http_select'"), [tls_v])
+    curs.execute(db_change('delete from other where name = "http_select"'))
+    curs.execute(db_change('insert into other (name, data, coverage) values ("http_select", ?, "")'), [tls_v])
 else:
     raise ValueError(what_i_do)
 

+ 4 - 4
lang/ko-KR.json

@@ -1,6 +1,6 @@
 {
     "language_tag": "ko-KR",
-    "delete_admin_group": "관리자 그룹 삭제",
+    "delete_admin_group": "권한 그룹 삭제",
     "document_name": "문서명",
     "non_login_alert": "비로그인 알림",
     "hide": "숨김",
@@ -153,7 +153,7 @@
     "admin": "관리자",
     "edit_filter_list": "편집 필터 목록",
     "wiki_skin": "위키 스킨",
-    "admin_group": "관리자 그룹",
+    "admin_group": "권한 그룹",
     "all": "전체",
     "error_skin_set": "사용 중인 스킨은 스킨 설정 기능을 지원하지 않습니다.",
     "error_skin_set_old": "일부 오래된 스킨은 구버전 링크를 이용해야만 작동할 수도 있습니다.",
@@ -200,7 +200,7 @@
     "topic_long_error": "토론 제목은 256자를 넘을 수 없습니다.",
     "error_401": "ACL 읽기 제한 문서 문구",
     "history": "역사",
-    "admin_group_list": "관리자 그룹 목록",
+    "admin_group_list": "권한 그룹 목록",
     "time": "시간",
     "password_search_text": "비밀번호 찾기 문구",
     "agreed_discussion": "합의된 토론",
@@ -325,7 +325,7 @@
     "all_register_num": "모든 가입 신청자의 수",
     "replace_move": "서로 바꾸기",
     "merge_move": "문서 병합",
-    "add_admin_group": "관리자 그룹 추가",
+    "add_admin_group": "권한 그룹 추가",
     "add_watchlist": "주시 문서 추가",
     "blocked_user": "차단된 사용자",
     "blocked_admin": "차단한 관리자",

+ 163 - 0
route/__init__.py

@@ -0,0 +1,163 @@
+from route.api_func_lang import api_func_lang
+from route.api_func_sha224 import api_func_sha224
+from route.api_image_view import api_image_view
+from route.api_raw import api_raw
+from route.api_recent_change import api_recent_change
+from route.api_recent_discuss import api_recent_discuss
+from route.api_search import api_search
+from route.api_setting import api_setting
+from route.api_skin_info import api_skin_info
+from route.api_title_index import api_title_index
+from route.api_topic import api_topic
+from route.api_user_info import api_user_info
+from route.api_version import api_version
+from route.api_w import api_w
+
+from route.bbs_edit import bbs_edit
+from route.bbs_main import bbs_main
+from route.bbs_make import bbs_make
+from route.bbs_w import bbs_w
+from route.bbs_w_post import bbs_w_post
+from route.bbs_w_set import bbs_w_set
+
+from route.edit import edit
+from route.edit_backlink_reset import edit_backlink_reset
+from route.edit_delete import edit_delete
+from route.edit_delete_file import edit_delete_file
+from route.edit_delete_multiple import edit_delete_multiple
+from route.edit_move import edit_move
+from route.edit_revert import edit_revert
+from route.edit_upload import edit_upload
+
+from route.filter_document import filter_document
+from route.filter_document_add import filter_document_add
+from route.filter_document_delete import filter_document_delete
+from route.filter_inter_wiki import filter_inter_wiki
+from route.filter_inter_wiki_add import filter_inter_wiki_add
+from route.filter_inter_wiki_delete import filter_inter_wiki_delete
+
+from route.give_admin_groups import give_admin_groups_2
+from route.give_auth import give_auth
+from route.give_delete_admin_group import give_delete_admin_group_2
+from route.give_user_ban import give_user_ban
+from route.give_user_check import give_user_check_2
+from route.give_user_check_delete import give_user_check_delete_2
+from route.give_user_fix import give_user_fix
+
+from route.list_acl import list_acl
+from route.list_admin import list_admin
+from route.list_admin_auth_use import list_admin_auth_use
+from route.list_admin_group import list_admin_group_2
+from route.list_image_file import list_image_file
+from route.list_long_page import list_long_page
+from route.list_old_page import list_old_page
+from route.list_please import list_please
+from route.list_title_index import list_title_index
+from route.list_user import list_user
+
+from route.login_find import login_find
+from route.login_find_email import login_find_email
+from route.login_find_email_check import login_find_email_check
+from route.login_find_key import login_find_key
+from route.login_login import login_login_2
+from route.login_login_2fa import login_login_2fa_2
+from route.login_login_2fa_email import login_login_2fa_email_2
+from route.login_logout import login_logout
+
+from route.login_register import login_register_2
+from route.login_register_email import login_register_email_2
+from route.login_register_email_check import login_register_email_check_2
+from route.login_register_submit import login_register_submit_2
+
+from route.main_func_easter_egg import main_func_easter_egg
+from route.main_func_error_404 import main_func_error_404
+
+from route.main_search import main_search
+from route.main_search_deep import main_search_deep
+from route.main_search_goto import main_search_goto
+
+from route.main_setting import main_setting
+from route.main_setting_acl import main_setting_acl
+from route.main_setting_external import main_setting_external
+from route.main_setting_head import main_setting_head
+from route.main_setting_main import main_setting_main
+from route.main_setting_main_logo import main_setting_main_logo
+from route.main_setting_phrase import main_setting_phrase
+from route.main_setting_robot import main_setting_robot
+from route.main_setting_sitemap import main_setting_sitemap
+from route.main_setting_skin_set import main_setting_skin_set
+from route.main_setting_top_menu import main_setting_top_menu
+
+from route.main_sys_restart import main_sys_restart
+from route.main_sys_shutdown import main_sys_shutdown
+from route.main_sys_update import main_sys_update
+
+from route.main_tool_admin import main_tool_admin
+from route.main_tool_other import main_tool_other
+from route.main_tool_redirect import main_tool_redirect
+
+from route.main_view import main_view
+from route.main_view_file import main_view_file
+from route.main_view_image import main_view_image
+
+from route.recent_app_submit import recent_app_submit_2
+
+from route.recent_block import recent_block_2
+from route.recent_change import recent_change
+from route.recent_discuss import recent_discuss
+from route.recent_history_add import recent_history_add
+from route.recent_history_delete import recent_history_delete
+from route.recent_history_hidden import recent_history_hidden
+from route.recent_history_reset import recent_history_reset
+from route.recent_history_send import recent_history_send
+from route.recent_history_tool import recent_history_tool
+from route.recent_record_reset import recent_record_reset
+from route.recent_record_topic import recent_record_topic
+
+from route.topic import topic
+from route.topic_comment_blind import topic_comment_blind
+from route.topic_comment_delete import topic_comment_delete
+from route.topic_comment_notice import topic_comment_notice
+from route.topic_comment_tool import topic_comment_tool
+from route.topic_list import topic_list
+from route.topic_tool import topic_tool
+from route.topic_tool_acl import topic_tool_acl
+from route.topic_tool_change import topic_tool_change
+from route.topic_tool_delete import topic_tool_delete
+from route.topic_tool_setting import topic_tool_setting
+
+from route.user_alarm import user_alarm
+from route.user_alarm_delete import user_alarm_delete
+from route.user_challenge import user_challenge
+from route.user_count import user_count
+from route.user_info import user_info
+
+from route.user_setting import user_setting
+from route.user_setting_email import user_setting_email_2
+from route.user_setting_email_check import user_setting_email_check_2
+from route.user_setting_email_delete import user_setting_email_delete
+from route.user_setting_head import user_setting_head
+from route.user_setting_head_reset import user_setting_head_reset
+from route.user_setting_key import user_setting_key
+from route.user_setting_key_delete import user_setting_key_delete
+from route.user_setting_pw import user_setting_pw
+from route.user_setting_skin_set import user_setting_skin_set
+from route.user_setting_skin_set_main import user_setting_skin_set_main
+from route.user_setting_top_menu import user_setting_top_menu
+
+from route.user_watch_list import user_watch_list
+from route.user_watch_list_name import user_watch_list_name
+
+from route.view_acl import view_acl
+from route.view_diff import view_diff
+from route.view_down import view_down
+from route.view_random import view_random
+from route.view_raw import view_raw_2
+from route.view_read import view_read
+from route.view_xref import view_xref
+
+from route.vote_add import vote_add
+from route.vote_close import vote_close
+from route.vote_end import vote_end
+from route.vote_list import vote_list
+from route.vote_select import vote_select

+ 59 - 29
route/api_topic.py

@@ -1,6 +1,7 @@
 from .tool.func import *
+from .bbs_w_post import bbs_w_post_make_thread
 
-def api_topic(topic_num = 1, tool = 'normal', num = ''):
+def api_topic(topic_num = 1, tool = 'normal', num = '', render = ''):
     with get_db_connect() as conn:
         curs = conn.cursor()
 
@@ -9,32 +10,19 @@ def api_topic(topic_num = 1, tool = 'normal', num = ''):
         if acl_check('', 'topic_view', topic_num) != 1:
             if tool == 'normal':
                 if num != '':
-                    curs.execute(db_change(
-                        "select id, data, date, ip, block, top from topic where code = ? and id + 0 = ? + 0 order by id + 0 asc"
-                    ), [
-                        topic_num,
-                        num
-                    ])
+                    curs.execute(db_change("select id, data, date, ip, block, top from topic where code = ? and id + 0 = ? + 0 order by id + 0 asc"), [topic_num, num])
                 else:
-                    curs.execute(db_change(
-                        "select id, data, date, ip, block, top from topic where code = ? order by id + 0 asc"
-                    ), [
-                        topic_num
-                    ])
-            elif tool == 'length':
+                    curs.execute(db_change("select id, data, date, ip, block, top from topic where code = ? order by id + 0 asc"), [topic_num])
+            elif tool == 'top':
+                curs.execute(db_change("select id, data, date, ip, block, top from topic where code = ? and top = 'O' order by id + 0 asc"), [topic_num])
+            else:
+                # tool == 'length'
                 curs.execute(db_change("select id from topic where code = ? order by id + 0 desc limit 1"), [topic_num])
                 db_data = curs.fetchall()
-
                 if db_data:
                     return flask.jsonify({ 'length' : db_data[0][0] })
                 else:
                     return flask.jsonify({})
-            else:
-                curs.execute(db_change(
-                    "select id, data, date, ip, block, top from topic where code = ? and top = 'O' order by id + 0 asc"
-                ), [
-                    topic_num
-                ])
 
             data = curs.fetchall()
             if data:
@@ -48,28 +36,70 @@ def api_topic(topic_num = 1, tool = 'normal', num = ''):
                     "ip_first" : ip_pas(data_f, 1),
                     "admin" : str(admin)
                 }
+                data_a['data'] = []
 
                 ip_a = ip_pas([i[3] for i in data])
                 ip_a_2 = ip_pas([i[3] for i in data], 1)
                 for i in data:
                     data_v = i[1] if i[4] != 'O' or admin == 1 else ''
+                    if data_v != '':
+                        data_v = render_set(
+                            doc_data = data_v, 
+                            data_type = 'api_view',
+                            data_in = 'topic_' + topic_num + '_' + i[0],
+                            doc_acl = 0
+                        )
+                        data_v[0] = re.sub(
+                            r'&lt;topic_a&gt;(?P<in>(?:(?!&lt;\/topic_a&gt;).)+)&lt;\/topic_a&gt;',
+                            '<a href="\g<in>">\g<in></a>',
+                            data_v[0]
+                        )
+                        data_v[0] = re.sub(
+                            r'&lt;topic_call&gt;@(?P<in>(?:(?!&lt;\/topic_call&gt;).)+)&lt;\/topic_call&gt;',
+                            '<a href="/w/user:\g<in>">@\g<in></a>',
+                            data_v[0]
+                        )
+                    else:
+                        data_v = ['', '']
+
+                    data_a['data'] += [{
+                        "id" : i[0],
 
-                    data_a[i[0]] = {
                         "data" : data_v,
                         "date" : i[2],
                         "ip" : ip_a_2[i[3]],
                         "blind" : i[4],
 
                         "ip_pas" : ip_a[i[3]],
-                        "data_pas" : render_set(
-                            doc_data = data_v, 
-                            data_type = 'api_view',
-                            data_in = 'topic_' + topic_num + '_' + i[0],
-                            doc_acl = 0
-                        )
-                    }
+                        "data_pas" : data_v
+                    }]
+
+                if render == '':
+                    return flask.jsonify(data_a)
+                else:
+                    data_r = ''
+                    if 'data' in data_a:
+                        for for_a in data_a['data']:
+                            if tool == 'top':
+                                color = 'red'
+                            else:
+                                if data_a['data_main']["ip_first"] == for_a["ip"]:
+                                    color = 'green'
+                                else:
+                                    color = 'default'
+
+                            data_r += bbs_w_post_make_thread(
+                                for_a["ip_pas"],
+                                '<a href="/thread/' + topic_num + '/comment/' + for_a["id"] + '/tool">(' + load_lang('tool') + ')</a> ' + for_a["date"],
+                                for_a["data_pas"][0] + for_a["data_pas"][1],
+                                for_a["id"],
+                                color = color,
+                                blind = for_a["blind"],
+                                add_style = ''
+                            )
+                            data_r += '<hr class="main_hr">'
 
-                return flask.jsonify(data_a)
+                    return flask.jsonify({ "data" : data_r })
             else:
                 return flask.jsonify({})
         else:

+ 163 - 0
route/bbs_edit.py

@@ -0,0 +1,163 @@
+from .tool.func import *
+
+def bbs_edit(bbs_num = '', post_num = '', do_type = ''):
+    with get_db_connect() as conn:
+        curs = conn.cursor()
+
+        bbs_num_str = str(bbs_num)
+        post_num_str = str(post_num)
+
+        ip = ip_check()
+
+        curs.execute(db_change('select set_id from bbs_set where set_id = ? and set_name = "bbs_name"'), [bbs_num_str])
+        if not curs.fetchall():
+            return redirect('/bbs/main')
+        
+        if post_num != '':
+            curs.execute(db_change('select set_data from bbs_data where set_name = "user_id" and set_id = ? and set_code = ?'), [bbs_num, post_num])
+            db_data = curs.fetchall()
+            if not db_data:
+                return redirect('/bbs/main')
+            else:
+                if not db_data[0][0] == ip and admin_check() != 1:
+                    return re_error('/ban')
+            
+        if acl_check(bbs_num_str, 'bbs_edit') == 1:
+            return redirect('/bbs/set/' + bbs_num_str)
+
+        if flask.request.method == 'POST' and do_type != 'preview':
+            if captcha_post(flask.request.form.get('g-recaptcha-response', flask.request.form.get('g-recaptcha', ''))) == 1:
+                return re_error('/error/13')
+            else:
+                captcha_post('', 0)
+        
+            if post_num == '':
+                curs.execute(db_change('select set_code from bbs_data where set_name = "title" and set_id = ? order by set_code + 0 desc'), [bbs_num_str])
+                db_data = curs.fetchall()
+                id_data = str(int(db_data[0][0]) + 1) if db_data else '1'
+            else:
+                id_data = post_num_str
+
+            title = flask.request.form.get('title', 'test')
+            title = 'test' if title == '' else title
+            data = flask.request.form.get('content', '')
+            if data == '':
+                # re_error로 대체 예정
+                return redirect('/bbs/w/' + bbs_num_str)
+            
+            date = get_time()
+
+            if post_num == '':
+                curs.execute(db_change("insert into bbs_data (set_name, set_code, set_id, set_data) values ('title', ?, ?, ?)"), [id_data, bbs_num_str, title])
+                curs.execute(db_change("insert into bbs_data (set_name, set_code, set_id, set_data) values ('data', ?, ?, ?)"), [id_data, bbs_num_str, data])
+                curs.execute(db_change("insert into bbs_data (set_name, set_code, set_id, set_data) values ('date', ?, ?, ?)"), [id_data, bbs_num_str, date])
+                curs.execute(db_change("insert into bbs_data (set_name, set_code, set_id, set_data) values ('user_id', ?, ?, ?)"), [id_data, bbs_num_str, ip])
+            else:
+                curs.execute(db_change("update bbs_data set set_data = ? where set_name = 'title' and set_code = ? and set_id = ?"), [title, post_num, bbs_num_str])
+                curs.execute(db_change("update bbs_data set set_data = ? where set_name = 'data' and set_code = ? and set_id = ?"), [data, id_data, bbs_num_str])
+                curs.execute(db_change("update bbs_data set set_data = ? where set_name = 'date' and set_code = ? and set_id = ?"), [date, id_data, bbs_num_str])
+
+            return redirect('/bbs/w/' + bbs_num_str + '/' + id_data)
+        else:
+            if do_type == 'preview':
+                title = flask.request.form.get('title', '')
+                data = flask.request.form.get('content', '')
+                data = data.replace('\r', '')
+
+                data_preview = render_set(
+                    doc_name = '', 
+                    doc_data = data,
+                    data_in = 'from'
+                )
+            else:
+                if post_num == '':
+                    title = ''
+                    data = ''
+                    data_preview = ''
+                else:
+                    curs.execute(db_change('select set_name, set_data, set_code from bbs_data where set_id = ? and set_code = ?'), [bbs_num, post_num])
+                    db_data = curs.fetchall()
+
+                    temp_id = ''
+                    temp_dict = {}
+
+                    for for_a in db_data + [['', '', '']]:
+                        if temp_id != for_a[2]:
+                            temp_id = for_a[2]
+                            temp_dict['code'] = for_a[2]
+
+                        temp_dict[for_a[0]] = for_a[1]
+
+                    title = temp_dict['title']
+                    data = temp_dict['data']
+                    data_preview = ''
+            
+            if post_num == '':
+                form_action = 'formaction="/bbs/edit/' + bbs_num_str + '"'
+                form_action_preview = 'formaction="/bbs/edit/preview/' + bbs_num_str + '"'
+            else:
+                form_action = 'formaction="/bbs/edit/' + bbs_num_str + '/' + post_num_str + '"'
+                form_action_preview = 'formaction="/bbs/edit/preview/' + bbs_num_str + '/' + post_num_str + '"'
+    
+            editor_top_text = '<a href="/edit_filter">(' + load_lang('edit_filter_rule') + ')</a>'
+            
+            monaco_on = get_main_skin_set(curs, flask.session, 'main_css_monaco', ip)
+            if monaco_on == 'use':
+                editor_display = 'style="display: none;"'
+                monaco_display = ''
+                add_get_file = '''
+                    <link   rel="stylesheet"
+                            data-name="vs/editor/editor.main" 
+                            href="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.37.1/min/vs/editor/editor.main.min.css">
+                    <script src="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.37.1/min/vs/loader.min.js"></script>
+                '''
+
+                editor_top_text += ' <a href="javascript:opennamu_edit_turn_off_monaco();">(' + load_lang('turn_off_monaco') + ')</a>'
+                
+                if flask.request.cookies.get('main_css_darkmode', '0') == '1':
+                    monaco_thema = 'vs-dark'
+                else:
+                    monaco_thema = ''
+                
+                add_script = 'do_monaco_init("' + monaco_thema + '");'
+            else:
+                editor_display = ''
+                monaco_display = 'style="display: none;"'
+                add_get_file = ''
+                add_script = 'opennamu_edit_turn_off_monaco();'
+
+            if editor_top_text != '':
+                editor_top_text += '<hr class="main_hr">'
+    
+            return easy_minify(flask.render_template(skin_check(), 
+                imp = [load_lang('bbs_edit'), wiki_set(), wiki_custom(), wiki_css([0, 0])],
+                data =  editor_top_text + add_get_file + '''
+                    <form method="post">
+                        <textarea style="display: none;" id="opennamu_edit_origin" name="doc_data_org"></textarea>
+
+                        <div>''' + edit_button('opennamu_edit_textarea', 'opennamu_monaco_editor') + '''</div>
+                        
+                        <input placeholder="''' + load_lang('bbs_title') + '''" name="title" value="''' + html.escape(title) + '''">
+                        <hr class="main_hr">
+
+                        <div id="opennamu_monaco_editor" class="opennamu_textarea_500" ''' + monaco_display + '''></div>
+                        <textarea id="opennamu_edit_textarea" ''' + editor_display + ''' class="opennamu_textarea_500" name="content">''' + html.escape(data) + '''</textarea>
+                        <hr class="main_hr">
+                        
+                        ''' + captcha_get() + ip_warning() + '''
+                        
+                        <button id="opennamu_save_button" type="submit" ''' + form_action + ''' onclick="do_monaco_to_textarea(); do_stop_exit_release();">''' + load_lang('save') + '''</button>
+                        <button id="opennamu_preview_button" type="submit" ''' + form_action_preview + ''' onclick="do_monaco_to_textarea(); do_stop_exit_release();">''' + load_lang('preview') + '''</button>
+                    </form>
+                    
+                    <hr class="main_hr">
+                    <div id="opennamu_preview_area">''' + data_preview + '''</div>
+                    
+                    <script>
+                        do_stop_exit();
+                        do_paste_image('opennamu_edit_textarea', 'opennamu_monaco_editor');
+                        ''' + add_script + '''
+                    </script>
+                ''',
+                menu = [['bbs/w/' + bbs_num_str, load_lang('return')]]
+            ))

+ 32 - 0
route/bbs_main.py

@@ -0,0 +1,32 @@
+from .tool.func import *
+
+def bbs_main():
+    with get_db_connect() as conn:
+        curs = conn.cursor()
+
+        curs.execute(db_change('select set_data, set_id from bbs_set where set_name = "bbs_name"'))
+        db_data = curs.fetchall()
+        
+        data = ''
+
+        if db_data:
+            data += '<ul class="opennamu_ul">'
+            for for_a in db_data:
+                curs.execute(db_change('select set_data from bbs_set where set_name = "bbs_type" and set_id = ?'), [for_a[1]])
+                db_data_2 = curs.fetchall()
+                bbs_type = db_data_2[0][0] if db_data_2 else 'comment'
+
+                data += '<li><a href="/bbs/w/' + for_a[1] + '">' + for_a[0] + ' (' + bbs_type + ')</a></li>'
+
+            data += '</ul>'
+
+        if admin_check() == 1:
+            menu = [['bbs/make', load_lang('add')]]
+        else:
+            menu = []
+
+        return easy_minify(flask.render_template(skin_check(),
+            imp = [load_lang('bbs_main'), wiki_set(), wiki_custom(), wiki_css([0, 0])],
+            data = data,
+            menu = [['other', load_lang('return')]] + menu
+        ))

+ 44 - 0
route/bbs_make.py

@@ -0,0 +1,44 @@
+from .tool.func import *
+
+def bbs_make():   
+    with get_db_connect() as conn:
+        curs = conn.cursor()
+
+        if admin_check() != 1:
+            return re_error('/error/3')
+        
+        if flask.request.method == 'POST':
+            
+            curs.execute(db_change('select set_id from bbs_set where set_name = "bbs_name" order by set_id + 0 desc'))
+            db_data = curs.fetchall()
+
+            bbs_num = str(int(db_data[0][0]) + 1) if db_data else '1'
+            bbs_name = flask.request.form.get('bbs_name', 'test')
+            bbs_type = flask.request.form.get('bbs_type', 'comment')
+            bbs_type = bbs_type if bbs_type in ['comment', 'thread'] else 'comment'
+
+            curs.execute(db_change("insert into bbs_set (set_name, set_code, set_id, set_data) values ('bbs_name', '', ?, ?)"), [bbs_num, bbs_name])
+            curs.execute(db_change("insert into bbs_set (set_name, set_code, set_id, set_data) values ('bbs_type', '', ?, ?)"), [bbs_num, bbs_type])
+
+            conn.commit()
+
+            return redirect('/bbs/main')
+        else:
+            return easy_minify(flask.render_template(skin_check(),
+                imp = [load_lang('bbs_make'), wiki_set(), wiki_custom(), wiki_css([0, 0])],
+                data = '''
+                    <form method="post">
+                        <input placeholder="''' + load_lang('bbs_name') + '''" name="bbs_name">
+                        <hr class="main_hr">
+                        
+                        <select name="bbs_type">
+                            <option value="comment">''' + load_lang('comment') + '''</option>
+                            <option value="thread">''' + load_lang('thread') + '''</option>
+                        </select>
+                        <hr class="main_hr">
+                        
+                        <button type="submit">''' + load_lang('save') + '''</button>
+                    </form>
+                ''',
+                menu = [['bbs/main', load_lang('return')]]
+            ))

+ 53 - 0
route/bbs_w.py

@@ -0,0 +1,53 @@
+from .tool.func import *
+
+def bbs_w(bbs_num = ''):
+    with get_db_connect() as conn:
+        curs = conn.cursor()
+
+        curs.execute(db_change('select set_id from bbs_set where set_id = ? and set_name = "bbs_name"'), [bbs_num])
+        if not curs.fetchall():
+            return redirect('/bbs/main')
+
+        bbs_num_str = str(bbs_num)
+
+        data = ''
+        data += '''
+            <table id="main_table_set">
+                <tr id="main_table_top_tr">
+                    <td id="main_table_width">''' + load_lang('version') + '''</td>
+                    <td id="main_table_width">''' + load_lang('editor') + '''</td>
+                    <td id="main_table_width">''' + load_lang('time') + '''</td>
+                </tr>
+        '''
+        
+        temp_id = ''
+        temp_dict = {}
+
+        curs.execute(db_change('select set_name, set_data, set_code from bbs_data where set_id = ? order by set_code + 0 desc'), [bbs_num])
+        db_data = curs.fetchall()
+        for for_a in db_data + [['', '', '']]:
+            if temp_id != for_a[2]:
+                if temp_id != '':
+                    data += '''
+                        <tr>
+                            <td>''' + temp_dict['code'] + '''</td>
+                            <td>''' + ip_pas(temp_dict['user_id']) + '''</td>
+                            <td>''' + temp_dict['date'] + '''</td>
+                        </tr>
+                        <tr>
+                            <td colspan="3">''' + ('<a href="/bbs/w/' + bbs_num_str + '/' + temp_dict['code'] + '">' + temp_dict['title'] + '</a>') + '''</td>
+                        </tr>
+                    '''
+
+                temp_id = for_a[2]
+                temp_dict['code'] = for_a[2]
+
+            temp_dict[for_a[0]] = for_a[1]
+
+        data += '</table>'
+
+        return easy_minify(flask.render_template(skin_check(),
+            imp = [load_lang('bbs_main'), wiki_set(), wiki_custom(), wiki_css([0, 0])],
+            data = data,
+            menu = [['bbs/main', load_lang('return')], ['bbs/edit/' + bbs_num_str, load_lang('add')], ['bbs/set/' + bbs_num_str, load_lang('setting')]]
+        ))

+ 375 - 0
route/bbs_w_post.py

@@ -0,0 +1,375 @@
+from .tool.func import *
+
+def bbs_w_post_make_thread(user_id, date, data, code, color = '', blind = '', add_style = ''):
+    if blind != '':
+        if data == '':
+            color_b = 'opennamu_comment_blind'
+        else:
+            color_b = 'opennamu_comment_blind_admin'
+    else:
+        color_b = 'opennamu_comment_blind_not'
+
+    return '''
+        <table class="opennamu_comment" style="''' + add_style + '''">
+            <tr>
+                <td class="opennamu_comment_color_''' + color + '''">
+                    <a href="#thread_shortcut" id="''' + code + '''">#''' + code + '''</a>
+                    ''' + user_id + '''
+                    <span style="float: right;">''' + date + '''</span>
+                </td>
+            </tr>
+            <tr>
+                <td class="''' + color_b + '''" id="opennamu_comment_data_main">
+                    ''' + data + '''
+                </td>
+            </tr>
+        </table>
+    '''
+
+def bbs_w_post(bbs_num = '', post_num = '', do_type = ''):
+    with get_db_connect() as conn:
+        curs = conn.cursor()
+
+        curs.execute(db_change('select set_name, set_data, set_code from bbs_data where set_id = ? and set_code = ?'), [bbs_num, post_num])
+        db_data = curs.fetchall()
+        if not db_data:
+            return redirect('/bbs/main')
+
+        bbs_num_str = str(bbs_num)
+        post_num_str = str(post_num)
+        bbs_comment_acl = acl_check(bbs_num_str, 'bbs_comment')
+        ip = ip_check()
+        
+        curs.execute(db_change('select set_data from bbs_set where set_id = ? and set_name = "bbs_type"'), [bbs_num])
+        db_data_2 = curs.fetchall()
+        if not db_data_2:
+            return redirect('/bbs/main')
+        elif db_data_2[0][0] == 'thread':
+            if flask.request.method == 'POST' and do_type != 'preview':
+                if bbs_comment_acl == 1:
+                    return redirect('/bbs/set/' + bbs_num_str)
+                
+                if captcha_post(flask.request.form.get('g-recaptcha-response', flask.request.form.get('g-recaptcha', ''))) == 1:
+                    return re_error('/error/13')
+                else:
+                    captcha_post('', 0)
+
+                set_id = bbs_num_str + '-' + post_num_str
+
+                curs.execute(db_change('select set_code from bbs_data where set_name = "comment" and set_id = ? order by set_code + 0 desc'), [set_id])
+                db_data = curs.fetchall()
+                id_data = str(int(db_data[0][0]) + 1) if db_data else '1'
+
+                data = flask.request.form.get('content', '')
+                if data == '':
+                    # re_error로 대체 예정
+                    return redirect('/bbs/w/' + bbs_num_str + '/' + post_num_str)
+                
+                date = get_time()
+
+                curs.execute(db_change("insert into bbs_data (set_name, set_code, set_id, set_data) values ('comment', ?, ?, ?)"), [id_data, set_id, data])
+                curs.execute(db_change("insert into bbs_data (set_name, set_code, set_id, set_data) values ('comment_date', ?, ?, ?)"), [id_data, set_id, date])
+                curs.execute(db_change("insert into bbs_data (set_name, set_code, set_id, set_data) values ('comment_user_id', ?, ?, ?)"), [id_data, set_id, ip])
+
+                conn.commit()
+
+                return redirect('/bbs/w/' + bbs_num_str + '/' + post_num_str + '#comment_' + str(int(id_data) + 1))
+            else:
+                if acl_check(bbs_num_str, 'bbs_view') == 1:
+                    return re_error('/ban')
+
+                if do_type == 'preview':
+                    text = flask.request.form.get('content', '')
+                    text = text.replace('\r', '')
+
+                    data_preview = render_set(
+                        doc_name = '', 
+                        doc_data = text,
+                        data_in = 'from'
+                    )
+                else:
+                    text = ''
+                    data_preview = ''
+                
+                temp_id = ''
+                temp_dict = {}
+
+                for for_a in db_data + [['', '', '']]:
+                    if temp_id != for_a[2]:
+                        temp_id = for_a[2]
+                        temp_dict['code'] = for_a[2]
+
+                    temp_dict[for_a[0]] = for_a[1]
+
+                count = 1
+
+                data = ''
+                data += '<h2>' + html.escape(temp_dict['title']) + '</h2>'
+                data += bbs_w_post_make_thread(
+                    ip_pas(temp_dict['user_id']),
+                    temp_dict['date'],
+                    render_set(
+                        doc_name = '', 
+                        doc_data = temp_dict['data'],
+                        data_in = 'from'
+                    ),
+                    '1',
+                    color = 'green'
+                )
+                data += '<hr class="main_hr">'
+
+                user_id = temp_dict['user_id']
+
+                temp_id = ''
+                temp_dict = {}
+
+                curs.execute(db_change('select set_name, set_data, set_code, set_id from bbs_data where (set_name = "comment" or set_name = "comment_date" or set_name = "comment_user_id") and set_id = ? order by set_code + 0 asc'), [bbs_num_str + '-' + post_num_str])
+                db_data = curs.fetchall()
+                for for_a in db_data + [['', '', '']]:
+                    if temp_id == '':
+                        temp_id = for_a[2]
+
+                    if temp_id != for_a[2]:
+                        temp_id = for_a[2]
+                        temp_dict['code'] = for_a[2]
+                        count += 1
+
+                        if user_id == temp_dict['comment_user_id']:
+                            color = 'green'
+                        else:
+                            color = 'default'
+
+                        data += bbs_w_post_make_thread(
+                            ip_pas(temp_dict['comment_user_id']),
+                            temp_dict['comment_date'],
+                            render_set(
+                                doc_name = '', 
+                                doc_data = temp_dict['comment'],
+                                data_in = 'from'
+                            ),
+                            str(count),
+                            color = color
+                        )
+                        data += '<hr class="main_hr">'
+
+                    temp_dict[for_a[0]] = for_a[1]
+
+                bbs_comment_form = ''
+                if bbs_comment_acl == 0:
+                    bbs_comment_form = '''                        
+                        <textarea name="content" id="opennamu_edit_textarea" class="opennamu_textarea_100">''' + html.escape(text) + '''</textarea>
+                        <hr class="main_hr">
+                        
+                        ''' + captcha_get() + ip_warning() + '''
+
+                        <button id="opennamu_save_button" formaction="/bbs/w/''' + bbs_num_str + '''/''' + post_num_str + '''" type="submit">''' + load_lang('send') + '''</button>
+                        <button id="opennamu_preview_button" formaction="/bbs/w/preview/''' + bbs_num_str + '''/''' + post_num_str + '''#opennamu_edit_textarea" type="submit">''' + load_lang('preview') + '''</button>
+                        <hr class="main_hr">
+                    '''
+
+                data += '''
+                    <form method="post">
+                        ''' + bbs_comment_form + '''
+                        ''' + data_preview + '''
+                    </form>
+                '''
+
+                return easy_minify(flask.render_template(skin_check(),
+                    imp = [load_lang('bbs_main'), wiki_set(), wiki_custom(), wiki_css([0, 0])],
+                    data = data,
+                    menu = [['bbs/w/' + bbs_num_str, load_lang('return')], ['bbs/edit/' + bbs_num_str + '/' + post_num_str, load_lang('edit')]]
+                ))
+        else:
+            # db_data_2[0][0] == 'comment'
+            if flask.request.method == 'POST' and do_type != 'preview':
+                if bbs_comment_acl == 1:
+                    return redirect('/bbs/set/' + bbs_num_str)
+                
+                if captcha_post(flask.request.form.get('g-recaptcha-response', flask.request.form.get('g-recaptcha', ''))) == 1:
+                    return re_error('/error/13')
+                else:
+                    captcha_post('', 0)
+                
+                select = flask.request.form.get('comment_select', 'default')
+                select = '' if select == 'default' else select
+                if select != '':
+                    select = select.split('-')
+                    if len(select) < 2:
+                        curs.execute(db_change('select set_code from bbs_data where set_name = "comment" and set_id = ? and set_code = ? limit 1'), [bbs_num_str + '-' + post_num_str, select[0]])
+                        if not curs.fetchall():
+                            return ''
+                        else:
+                            set_id = bbs_num_str + '-' + post_num_str + '-' + select[0]
+                    else:
+                        curs.execute(db_change('select set_code from bbs_data where set_name = "comment" and set_id = ? and set_code = ? limit 1'), [bbs_num_str + '-' + post_num_str + '-' + '-'.join(select[0:len(select) - 1]), select[len(select) - 1]])
+                        if not curs.fetchall():
+                            return ''
+                        else:
+                            set_id = bbs_num_str + '-' + post_num_str + '-' + '-'.join(select)
+                else:
+                    set_id = bbs_num_str + '-' + post_num_str
+
+                curs.execute(db_change('select set_code from bbs_data where set_name = "comment" and set_id = ? order by set_code + 0 desc'), [set_id])
+                db_data = curs.fetchall()
+                id_data = str(int(db_data[0][0]) + 1) if db_data else '1'
+
+                data = flask.request.form.get('content', '')
+                if data == '':
+                    # re_error로 대체 예정
+                    return redirect('/bbs/w/' + bbs_num_str + '/' + post_num_str)
+
+                date = get_time()
+
+                curs.execute(db_change("insert into bbs_data (set_name, set_code, set_id, set_data) values ('comment', ?, ?, ?)"), [id_data, set_id, data])
+                curs.execute(db_change("insert into bbs_data (set_name, set_code, set_id, set_data) values ('comment_date', ?, ?, ?)"), [id_data, set_id, date])
+                curs.execute(db_change("insert into bbs_data (set_name, set_code, set_id, set_data) values ('comment_user_id', ?, ?, ?)"), [id_data, set_id, ip])
+
+                conn.commit()
+            
+                if set_id == '':
+                    return redirect('/bbs/w/' + bbs_num_str + '/' + post_num_str + '#comment_' + id_data)
+                else:
+                    set_id = re.sub(r'^[0-9]+-[0-9]+-?', '', set_id)
+                    return redirect('/bbs/w/' + bbs_num_str + '/' + post_num_str + '#comment_' + set_id + '-' + id_data)
+            else:
+                if acl_check(bbs_num_str, 'bbs_view') == 1:
+                    return re_error('/ban')
+                    
+                if do_type == 'preview':
+                    text = flask.request.form.get('content', '')
+                    text = text.replace('\r', '')
+
+                    data_preview = render_set(
+                        doc_name = '', 
+                        doc_data = text,
+                        data_in = 'from'
+                    )
+                else:
+                    text = ''
+                    data_preview = ''
+
+                temp_id = ''
+                temp_dict = {}
+
+                for for_a in db_data + [['', '', '']]:
+                    if temp_id != for_a[2]:
+                        temp_id = for_a[2]
+                        temp_dict['code'] = for_a[2]
+
+                    temp_dict[for_a[0]] = for_a[1]
+
+                data = ''
+                data += '<h2>' + html.escape(temp_dict['title']) + '</h2>'
+                data += bbs_w_post_make_thread(
+                    ip_pas(temp_dict['user_id']),
+                    temp_dict['date'],
+                    render_set(
+                        doc_name = '', 
+                        doc_data = temp_dict['data'],
+                        data_in = 'from'
+                    ),
+                    '0',
+                    color = 'red'
+                )
+
+                user_id = temp_dict['user_id']
+                temp_id = ''
+                temp_dict = {}
+                comment_data = ''
+
+                comment_select = '<hr class="main_hr"><select name="comment_select">'
+                comment_select += '<option value="default">' + load_lang('normal') + '</option>'
+
+                curs.execute(db_change('select set_name, set_data, set_code, set_id from bbs_data where (set_name = "comment" or set_name = "comment_date" or set_name = "comment_user_id") and set_id = ? order by set_code + 0 asc'), [bbs_num_str + '-' + post_num_str])
+                db_data = curs.fetchall()
+                if db_data:
+                    data += '<hr class="main_hr"><hr>'
+                else:
+                    db_data = []
+
+                for_a = 0
+                db_data_2 = db_data + [['', '', '', '']]
+                db_data_len = len(db_data_2)
+                comment_count = 0
+                comment_add_count = 0
+                while(for_a < db_data_len):
+                    if temp_id != (db_data_2[for_a][3] + '-' + db_data_2[for_a][2]):
+                        if temp_id != '':
+                            temp_dict['code'] = temp_id
+                            temp_dict['code'] = re.sub(r'^[0-9]+-[0-9]+-', '', temp_dict['code'])
+
+                            if user_id == temp_dict['comment_user_id']:
+                                color = 'green'
+                            else:
+                                color = 'default'
+
+                            margin_count = temp_dict['code'].count('-')
+                            if margin_count == 0:
+                                comment_count += 1
+                            else:
+                                comment_add_count += 1
+
+                            comment_data += '<span style="padding-left: 20px;"></span>' * margin_count
+                            comment_data += bbs_w_post_make_thread(
+                                ip_pas(temp_dict['comment_user_id']),
+                                temp_dict['comment_date'],
+                                render_set(
+                                    doc_name = '', 
+                                    doc_data = temp_dict['comment'],
+                                    data_in = 'from'
+                                ),
+                                temp_dict['code'],
+                                color = color,
+                                add_style = 'width: calc(100% - ' + str(margin_count * 20) + 'px);'
+                            )
+
+                            comment_select += '<option value="' + temp_dict['code'] + '">' + temp_dict['code'] + '</option>'
+
+                            curs.execute(db_change('select set_name, set_data, set_code, set_id from bbs_data where (set_name = "comment" or set_name = "comment_date" or set_name = "comment_user_id") and set_id = ? order by set_code + 0 asc'), [bbs_num_str + '-' + post_num_str + '-' + temp_dict['code']])
+                            db_data = curs.fetchall()
+                            if db_data:
+                                db_data_2 = db_data_2[:for_a] + db_data + db_data_2[for_a:]
+                                db_data_len += len(db_data)
+
+                            if db_data_2[for_a][0] != '':
+                                comment_data += '<hr class="main_hr">'
+
+                        temp_id = db_data_2[for_a][3] + '-' + db_data_2[for_a][2]
+
+                    temp_dict[db_data_2[for_a][0]] = db_data_2[for_a][1]
+                    for_a += 1
+
+                comment_select += '</select>'
+                if comment_data != '':
+                    data += load_lang('comment') + ' : ' + str(comment_count) + '<hr class="main_hr">'
+                    data += load_lang('reply') + ' : ' + str(comment_add_count) + '<hr class="main_hr">'
+                    data += comment_data
+
+                bbs_comment_form = ''
+                if bbs_comment_acl == 0:
+                    bbs_comment_form = '''
+                        ''' + comment_select + '''
+                        <hr class="main_hr">
+                        
+                        <textarea name="content" id="opennamu_edit_textarea" class="opennamu_textarea_100">''' + html.escape(text) + '''</textarea>
+                        <hr class="main_hr">
+                        
+                        ''' + captcha_get() + ip_warning() + '''
+
+                        <button id="opennamu_save_button" formaction="/bbs/w/''' + bbs_num_str + '''/''' + post_num_str + '''" type="submit">''' + load_lang('send') + '''</button>
+                        <button id="opennamu_preview_button" formaction="/bbs/w/preview/''' + bbs_num_str + '''/''' + post_num_str + '''#opennamu_edit_textarea" type="submit">''' + load_lang('preview') + '''</button>
+                        <hr class="main_hr">
+                    '''
+
+                data += '''
+                    <form method="post">
+                        ''' + bbs_comment_form + '''
+                        ''' + data_preview + '''
+                    </form>
+                '''
+
+                return easy_minify(flask.render_template(skin_check(),
+                    imp = [load_lang('bbs_main'), wiki_set(), wiki_custom(), wiki_css([0, 0])],
+                    data = data,
+                    menu = [['bbs/w/' + bbs_num_str, load_lang('return')], ['bbs/edit/' + bbs_num_str + '/' + post_num_str, load_lang('edit')]]
+                ))

+ 94 - 0
route/bbs_w_set.py

@@ -0,0 +1,94 @@
+from .tool.func import *
+
+def bbs_w_set(bbs_num = ''):
+    with get_db_connect() as conn:
+        curs = conn.cursor()
+
+        curs.execute(db_change('select set_id from bbs_set where set_id = ? and set_name = "bbs_name"'), [bbs_num])
+        if not curs.fetchall():
+            return redirect('/bbs/main')
+
+        i_list = {
+            1 : 'bbs_acl',
+            2 : 'bbs_edit_acl',
+            3 : 'bbs_comment_acl',
+            4 : 'bbs_view_acl'
+        }
+        bbs_num_str = str(bbs_num)
+
+        if flask.request.method == 'POST':
+            if admin_check(None, 'bbs_set (acl)') != 1:
+                return re_error('/ban')
+            else:
+                for i in i_list:
+                    curs.execute(db_change("update bbs_set set set_data = ? where set_name = ? and set_id = ?"), [
+                        flask.request.form.get(i_list[i], 'normal'),
+                        i_list[i],
+                        bbs_num
+                    ])
+
+                conn.commit()
+
+                return redirect('/bbs/set/' + bbs_num_str)
+        else:
+            d_list = {}
+
+            if admin_check() != 1:
+                disable = 'disabled'
+            else:
+                disable = ''
+
+            for i in i_list:
+                curs.execute(db_change('select set_data from bbs_set where set_name = ? and set_id = ?'), [i_list[i], bbs_num])
+                sql_d = curs.fetchall()
+                if sql_d:
+                    d_list[i] = sql_d[0][0]
+                else:
+                    curs.execute(db_change('insert into bbs_set (set_name, set_code, set_id, set_data) values (?, "", ?, ?)'), [i_list[i], bbs_num, 'normal'])
+                    d_list[i] = 'normal'
+
+            conn.commit()
+
+            acl_div = []
+            for i in range(0, len(i_list)):
+                acl_div += ['']
+
+            acl_list = get_acl_list()
+            for i in range(0, len(i_list)):
+                for data_list in acl_list:
+                    if data_list == d_list[i + 1]:
+                        check = 'selected="selected"'
+                    else:
+                        check = ''
+
+                    acl_div[i] += '<option value="' + data_list + '" ' + check + '>' + (data_list if data_list != '' else 'normal') + '</option>'
+
+            return easy_minify(flask.render_template(skin_check(),
+                imp = [load_lang('main_acl_setting'), wiki_set(), wiki_custom(), wiki_css([0, 0])],
+                data = render_simple_set('''
+                    <form method="post">
+                        <hr class="main_hr">
+                        <a href="/acl/TEST#exp">(''' + load_lang('reference') + ''')</a>
+                        
+                        <h2>''' + load_lang('acl') + '''</h2>
+                        <h3>''' + load_lang('bbs_view_acl') + '''</h3>
+                        <select ''' + disable + ''' name="bbs_view_acl">''' + acl_div[3] + '''</select>
+
+                        <h4>''' + load_lang('bbs_acl') + '''</h4>
+                        <select ''' + disable + ''' name="bbs_acl">''' + acl_div[0] + '''</select>
+
+                        <h5>''' + load_lang('bbs_edit_acl') + '''</h5>
+                        <select ''' + disable + ''' name="bbs_edit_acl">''' + acl_div[1] + '''</select>
+
+                        <h5>''' + load_lang('bbs_comment_acl') + '''</h5>
+                        <select ''' + disable + ''' name="bbs_comment_acl">''' + acl_div[2] + '''</select>
+
+                        <h2>''' + load_lang('markup') + '''</h2>
+                        ''' + load_lang('not_working') + '''
+                        
+                        <hr class="main_hr">
+                        <button id="opennamu_save_button" type="submit">''' + load_lang('save') + '''</button>
+                    </form>
+                '''),
+                menu = [['bbs/w/' + bbs_num_str, load_lang('return')]]
+            ))

+ 8 - 7
route/give_admin.py → route/give_auth.py

@@ -1,10 +1,11 @@
 from .tool.func import *
 
-def give_admin_2(name):
+def give_auth(name):
     with get_db_connect() as conn:
         curs = conn.cursor()
 
-        owner = admin_check()
+        owner_auth = admin_check()
+        admin_auth = admin_check(7)
 
         curs.execute(db_change("select data from user_set where id = ? and name = 'acl'"), [name])
         user_acl = curs.fetchall()
@@ -13,7 +14,7 @@ def give_admin_2(name):
         else:
             user_acl = user_acl[0][0]
 
-        if owner != 1:
+        if owner_auth != 1:
             curs.execute(db_change('select name from alist where name = ? and acl = "owner"'), [user_acl])
             if curs.fetchall():
                 return re_error('/error/3')
@@ -31,7 +32,7 @@ def give_admin_2(name):
                 select_data = flask.request.form.get('select', 'X')
 
             curs.execute(db_change('select name from alist where name = ? and acl = "owner"'), [select_data])
-            if owner != 1 and curs.fetchall():
+            if owner_auth != 1 and curs.fetchall():
                 return re_error('/error/3')
 
             curs.execute(db_change("update user_set set data = ? where id = ? and name = 'acl'"), [
@@ -41,12 +42,12 @@ def give_admin_2(name):
 
             conn.commit()
 
-            return redirect('/admin/' + url_pas(name))
+            return redirect('/auth/give/' + url_pas(name))
         else:
-            if admin_check(7) != 1:
+            if admin_auth != 1:
                 return re_error('/error/3')
 
-            div = '<option value="X">X</option>'
+            div = '<option value="X">' + load_lang('normal') + '</option>'
 
             curs.execute(db_change('select distinct name from alist order by name asc'))
             for data in curs.fetchall():

+ 4 - 4
route/list_acl.py

@@ -1,11 +1,11 @@
 from .tool.func import *
 
-def list_acl_2():
+def list_acl(arg_num = 1):
     with get_db_connect() as conn:
         curs = conn.cursor()
 
-        num = int(number_check(flask.request.args.get('num', '1')))
-        sql_num = (num * 50 - 50) if num * 50 > 0 else 0
+        sql_num = (arg_num * 50 - 50) if arg_num * 50 > 0 else 0
+
         div = '<ul class="opennamu_ul">'
 
         curs.execute(db_change(
@@ -30,7 +30,7 @@ def list_acl_2():
             ''
 
         div += '</ul>'
-        div += next_fix('/acl_list?num=', num, list_data)
+        div += next_fix('/list/document/acl/', num, list_data)
 
         return easy_minify(flask.render_template(skin_check(),
             imp = [load_lang('acl_document_list'), wiki_set(), wiki_custom(), wiki_css([0, 0])],

+ 1 - 1
route/list_admin.py

@@ -1,6 +1,6 @@
 from .tool.func import *
 
-def list_admin_2():
+def list_admin():
     with get_db_connect() as conn:
         curs = conn.cursor()
 

+ 1 - 1
route/list_admin_use.py → route/list_admin_auth_use.py

@@ -1,6 +1,6 @@
 from .tool.func import *
 
-def list_admin_use(arg_num = 1, arg_search = 'normal'):
+def list_admin_auth_use(arg_num = 1, arg_search = 'normal'):
     with get_db_connect() as conn:
         curs = conn.cursor()
 

+ 2 - 2
route/list_image_file.py

@@ -1,6 +1,6 @@
 from .tool.func import *
 
-def list_image_file_2():
+def list_image_file():
     with get_db_connect() as conn:
         curs = conn.cursor()
 
@@ -15,7 +15,7 @@ def list_image_file_2():
         for data in data_list:
             list_data += '<li><a href="/w/' + url_pas(data[0]) + '">' + html.escape(data[0]) + '</a></li>'
 
-        list_data += next_fix('/image_file_list?num=', num, data_list)
+        list_data += next_fix('/list/file/', num, data_list)
 
         return easy_minify(flask.render_template(skin_check(),
             imp = [load_lang('image_file_list'), wiki_set(), wiki_custom(), wiki_css([0, 0])],

+ 1 - 1
route/list_long_page.py

@@ -1,6 +1,6 @@
 from .tool.func import *
 
-def list_long_page_2(tool):
+def list_long_page(tool = 'long_page'):
     with get_db_connect() as conn:
         curs = conn.cursor()
 

+ 3 - 4
route/list_please.py

@@ -1,11 +1,10 @@
 from .tool.func import *
 
-def list_please_2():
+def list_please(arg_num = 1):
     with get_db_connect() as conn:
         curs = conn.cursor()
 
-        num = int(number_check(flask.request.args.get('num', '1')))
-        sql_num = (num * 50 - 50) if num * 50 > 0 else 0
+        sql_num = (arg_num * 50 - 50) if arg_num * 50 > 0 else 0
 
         curs.execute(db_change('select data from other where name = "count_all_title"'))
         if int(curs.fetchall()[0][0]) > 30000:
@@ -23,7 +22,7 @@ def list_please_2():
                 '</li>' + \
             ''
 
-        div += '</ul>' + next_fix('/please?num=', num, data_list)
+        div += '</ul>' + next_fix('/list/document/need/', num, data_list)
 
         return easy_minify(flask.render_template(skin_check(),
             imp = [load_lang('need_document'), wiki_set(), wiki_custom(), wiki_css([0, 0])],

+ 3 - 4
route/list_user.py

@@ -1,11 +1,10 @@
 from .tool.func import *
 
-def list_user_2():
+def list_user(arg_num = 1):
     with get_db_connect() as conn:
         curs = conn.cursor()
 
-        num = int(number_check(flask.request.args.get('num', '1')))
-        sql_num = (num * 50 - 50) if num * 50 > 0 else 0
+        sql_num = (arg_num * 50 - 50) if arg_num * 50 > 0 else 0
 
         list_data = '<ul class="opennamu_ul">'
 
@@ -18,7 +17,7 @@ def list_user_2():
                 '</li>' + \
             ''
 
-        list_data += '</ul>' + next_fix('/user_log?num=', num, user_list)
+        list_data += '</ul>' + next_fix('/list/user/', num, user_list)
 
         return easy_minify(flask.render_template(skin_check(),
             imp = [load_lang('member_list'), wiki_set(), wiki_custom(), wiki_css([0, 0])],

+ 3 - 3
route/main_search_deep.py

@@ -26,7 +26,7 @@ def main_search_deep(name = 'Test', search_type = 'title', num = 1):
         if name_new != '':
             div += ' <a href="/search/1/' + url_pas(name_new) + '">(' + name_new + ')</a>'
 
-        curs.execute(db_change("select title from data where title = ?"), [name])
+        curs.execute(db_change("select title from data where title = ? collate nocase"), [name])
         link_id = '' if curs.fetchall() else 'class="opennamu_not_exist_link"'
 
         div += '''
@@ -40,11 +40,11 @@ def main_search_deep(name = 'Test', search_type = 'title', num = 1):
         '''
 
         if search_type == 'title':
-            curs.execute(db_change("select title from data where title like ? order by title limit ?, 50"),
+            curs.execute(db_change("select title from data where title like ? collate nocase order by title limit ?, 50"),
                 ['%' + name + '%', sql_num]
             )
         else:
-            curs.execute(db_change("select title from data where data like ? order by title limit ?, 50"),
+            curs.execute(db_change("select title from data where data like ? collate nocase order by title limit ?, 50"),
                 ['%' + name + '%', sql_num]
             )
 

+ 4 - 4
route/main_search_goto.py

@@ -9,9 +9,9 @@ def main_search_goto(name = 'Test'):
         else:
             data = name
 
-        curs.execute(db_change("select title from data where title = ?"), [data])
-        t_data = curs.fetchall()
-        if t_data:
-            return redirect('/w/' + url_pas(data))
+        curs.execute(db_change("select title from data where title = ? collate nocase"), [data])
+        db_data = curs.fetchall()
+        if db_data:
+            return redirect('/w/' + url_pas(db_data[0][0]))
         else:
             return redirect('/search/' + url_pas(data))

+ 0 - 1
route/main_setting_acl.py

@@ -46,7 +46,6 @@ def main_setting_acl():
                     d_list[i] = sql_d[0][0]
                 else:
                     curs.execute(db_change('insert into other (name, data, coverage) values (?, ?, "")'), [i_list[i], 'normal'])
-
                     d_list[i] = 'normal'
 
             conn.commit()

+ 0 - 1
route/main_setting_external.py

@@ -43,7 +43,6 @@ def main_setting_external():
                     d_list += [sql_d[0][0]]
                 else:
                     curs.execute(db_change('insert into other (name, data, coverage) values (?, ?, "")'), [i, ''])
-
                     d_list += ['']
 
                 x += 1

+ 8 - 2
route/main_setting_main.py

@@ -35,7 +35,8 @@ def main_setting_main(db_set):
             31 : ['wiki_access_password_need', ''],
             32 : ['wiki_access_password', ''],
             33 : ['history_recording_off', ''],
-            34 : ['namumark_compatible', '']
+            34 : ['namumark_compatible', ''],
+            35 : ['user_name_view', '']
         }
 
         if flask.request.method == 'POST':
@@ -85,7 +86,7 @@ def main_setting_main(db_set):
                 else:
                     tls_select += '<option value="' + tls_select_one + '">' + tls_select_one + '</option>'
 
-            check_box_div = ['', '', '', '', '', '', '', '', '', '', '']
+            check_box_div = ['', '', '', '', '', '', '', '', '', '', '', '']
             for i in range(0, len(check_box_div)):
                 if i == 0:
                     acl_num = 7
@@ -107,6 +108,8 @@ def main_setting_main(db_set):
                     acl_num = 33
                 elif i == 10:
                     acl_num = 34
+                elif i == 11:
+                    acl_num = 35
 
                 if d_list[acl_num]:
                     check_box_div[i] = 'checked="checked"'
@@ -197,6 +200,9 @@ def main_setting_main(db_set):
                         <input type="checkbox" name="ip_view" ''' + check_box_div[1] + '''> ''' + load_lang('hide_ip') + '''
                         <hr class="main_hr">
 
+                        <input type="checkbox" name="user_name_view" ''' + check_box_div[11] + '''> ''' + load_lang('hide_user_name') + '''
+                        <hr class="main_hr">
+
                         <input type="checkbox" name="requires_approval" ''' + check_box_div[3] + '''> ''' + load_lang('requires_approval') + '''
                         <hr class="main_hr">
 

+ 0 - 1
route/main_setting_phrase.py

@@ -52,7 +52,6 @@ def main_setting_phrase():
                     d_list += [sql_d[0][0]]
                 else:
                     curs.execute(db_change('insert into other (name, data, coverage) values (?, ?, "")'), [i, ''])
-
                     d_list += ['']
 
             conn.commit()

+ 7 - 7
route/main_tool_other.py

@@ -13,7 +13,7 @@ def main_tool_other():
                 <h2>''' + load_lang('list') + '''</h2>
                 <h3>''' + load_lang('admin') + '''</h3>
                 <ul class="opennamu_ul">               
-                    <li><a href="/admin_list">''' + load_lang('admin_list') + '''</a></li>
+                    <li><a href="/list/admin">''' + load_lang('admin_list') + '''</a></li>
                     <li><a href="/list/admin/auth_use">''' + load_lang('authority_use_list') + '''</a></li>
                 </ul>
                 <h3>''' + load_lang('discussion') + '''</h3>
@@ -24,20 +24,20 @@ def main_tool_other():
                 <ul class="opennamu_ul">
                     <li><a href="/recent_change">''' + load_lang('recent_change') + '''</a></li>
                     <li><a href="/list/document/all">''' + load_lang('all_document_list') + '''</a></li>
-                    <li><a href="/acl_list">''' + load_lang('acl_document_list') + '''</a></li>
-                    <li><a href="/please">''' + load_lang('need_document') + '''</a></li>
-                    <li><a href="/long_page">''' + load_lang('long_page') + '''</a></li>
-                    <li><a href="/short_page">''' + load_lang('short_page') + '''</a></li>
+                    <li><a href="/list/document/acl">''' + load_lang('acl_document_list') + '''</a></li>
+                    <li><a href="/list/document/need">''' + load_lang('need_document') + '''</a></li>
+                    <li><a href="/list/document/long">''' + load_lang('long_page') + '''</a></li>
+                    <li><a href="/list/document/short">''' + load_lang('short_page') + '''</a></li>
                     <li><a href="/list/document/old">''' + load_lang('old_page') + '''</a></li>
                 </ul>
                 <h3>''' + load_lang('user') + '''</h3>
                 <ul class="opennamu_ul">
                     <li><a href="/block_log">''' + load_lang('recent_ban') + '''</a></li>
-                    <li><a href="/user_log">''' + load_lang('member_list') + '''</a></li>
+                    <li><a href="/list/user">''' + load_lang('member_list') + '''</a></li>
                 </ul>
                 <h3>''' + load_lang('other') + '''</h3>
                 <ul class="opennamu_ul">
-                    <li><a href="/image_file_list">''' + load_lang('image_file_list') + '''</a></li>
+                    <li><a href="/list/file">''' + load_lang('image_file_list') + '''</a></li>
                     <li><a href="/vote">''' + load_lang('vote_list') + '''</a></li>
                     <li><a href="/bbs/main">''' + load_lang('bbs_main') + '''</a></li>
                 </ul>

+ 19 - 19
route/main_tool_redirect.py

@@ -3,28 +3,28 @@ from .tool.func import *
 def main_tool_redirect(num = 1, add_2 = ''):
     with get_db_connect() as conn:
         title_list = {
-            0 : [load_lang('document_name'), 'acl', load_lang('acl')],
-            1 : [0, 'check', load_lang('check')],
-            2 : [load_lang('file_name'), 'file_filter/add', load_lang('file_filter_add')],
-            3 : [0, 'admin', load_lang('authorize')],
-            4 : [0, 'record', load_lang('edit_record')],
-            5 : [0, 'record/topic', load_lang('discussion_record')],
-            6 : [load_lang('name'), 'admin_plus', load_lang('add_admin_group')],
-            7 : [load_lang('name'), 'edit_filter/add', load_lang('edit_filter_add')],
-            8 : [load_lang('document_name'), 'search', load_lang('search')],
-            9 : [0, 'block_log/user', load_lang('blocked_user')],
-            10 : [0, 'block_log/admin', load_lang('blocked_admin')],
-            11 : [load_lang('document_name'), 'watch_list', load_lang('add_watchlist')],
-            12 : [load_lang('compare_target'), 'check', load_lang('compare_target')],
-            13 : [load_lang('document_name'), 'edit', load_lang('load')],
-            14 : [load_lang('document_name'), 'star_doc', load_lang('add_star_doc')],
-            15 : [load_lang('name_or_ip_or_regex'), 'auth/give/ban', load_lang('release')],
-            16 : [0, 'auth/give/fix', load_lang('user_fix')],
+            0 : [load_lang('document_name'), '/acl', load_lang('acl')],
+            1 : [0, '/check', load_lang('check')],
+            2 : [load_lang('file_name'), '/file_filter/add', load_lang('file_filter_add')],
+            3 : [0, '/auth/give', load_lang('authorize')],
+            4 : [0, '/record', load_lang('edit_record')],
+            5 : [0, '/record/topic', load_lang('discussion_record')],
+            6 : [load_lang('name'), '/admin_plus', load_lang('add_admin_group')],
+            7 : [load_lang('name'), '/edit_filter/add', load_lang('edit_filter_add')],
+            8 : [load_lang('document_name'), '/search', load_lang('search')],
+            9 : [0, '/block_log/user', load_lang('blocked_user')],
+            10 : [0, '/block_log/admin', load_lang('blocked_admin')],
+            11 : [load_lang('document_name'), '/watch_list', load_lang('add_watchlist')],
+            12 : [load_lang('compare_target'), '/check', load_lang('compare_target')],
+            13 : [load_lang('document_name'), '/edit', load_lang('load')],
+            14 : [load_lang('document_name'), '/star_doc', load_lang('add_star_doc')],
+            15 : [load_lang('name_or_ip_or_regex'), '/auth/give/ban', load_lang('release')],
+            16 : [0, '/auth/give/fix', load_lang('user_fix')],
         }
         
         if num == 1:
             return redirect('/manager')
-        elif not num - 1 > len(title_list):
+        elif num - 1 <= len(title_list):
             num -= 2
 
             add_1 = flask.request.form.get('name', 'test')
@@ -35,7 +35,7 @@ def main_tool_redirect(num = 1, add_2 = ''):
                 elif flask.request.form.get('regex', '') != '':
                     return redirect('/auth/give/ban_regex/' + url_pas(add_1))
                 else:
-                    return redirect('/' + title_list[num][1] + '/' + url_pas(add_1))
+                    return redirect(title_list[num][1] + '/' + url_pas(add_1))
             else:
                 if title_list[num][0] == 0:
                     placeholder = load_lang('user_name')

+ 61 - 19
route/tool/func.py

@@ -174,7 +174,10 @@ class get_db_connect:
             )
             curs = self.conn.cursor()
 
-            self.conn.select_db(self.db_set['name'])
+            try:
+                self.conn.select_db(self.db_set['name'])
+            except:
+                pass
 
         load_conn(self.conn)
         return self.conn
@@ -1108,7 +1111,7 @@ def wiki_css(data):
     data_css += '<script defer src="/views/main_css/js/func/shortcut.js?ver=' + data_css_ver + '"></script>'
     
     # Route JS + Defer
-    data_css += '<script defer src="/views/main_css/js/route/thread.js?ver=' + data_css_ver + '"></script>'
+
     
     # Route JS
     data_css += '<script src="/views/main_css/js/route/editor.js?ver=' + data_css_ver + '"></script>'
@@ -1754,6 +1757,9 @@ def acl_check(name = 'test', tool = '', topic_num = '1'):
     elif tool in ['document_edit', 'document_move', 'document_delete']:
         if acl_check(name, '') == 1:
             return 1
+    elif tool in ['bbs_edit', 'bbs_comment']:
+        if acl_check(name, 'bbs_view') == 1:
+            return 1
     elif tool == 'topic':
         curs.execute(db_change("select title from rd where code = ?"), [topic_num])
         name = curs.fetchall()
@@ -1761,7 +1767,7 @@ def acl_check(name = 'test', tool = '', topic_num = '1'):
 
     if tool in ['topic']:
         end = 3
-    elif tool in ['render', 'vote', '', 'document_edit', 'document_move', 'document_delete']:
+    elif tool in ['render', 'vote', '', 'document_edit', 'document_move', 'document_delete', 'document_edit', 'bbs_edit', 'bbs_comment']:
         end = 2
     else:
         end = 1
@@ -1873,6 +1879,22 @@ def acl_check(name = 'test', tool = '', topic_num = '1'):
             ))
 
             num = 'all'
+        elif tool == 'bbs_edit':
+            if i == 0:
+                curs.execute(db_change('select set_data from bbs_set where set_name = "bbs_edit_acl" and set_id = ?'), [name])
+            else:
+                curs.execute(db_change('select set_data from bbs_set where set_name = "bbs_acl" and set_id = ?'), [name])
+
+            num = 'all'
+        elif tool == 'bbs_comment':
+            if i == 0:
+                curs.execute(db_change('select set_data from bbs_set where set_name = "bbs_comment_acl" and set_id = ?'), [name])
+            else:
+                curs.execute(db_change('select set_data from bbs_set where set_name = "bbs_acl" and set_id = ?'), [name])
+
+            num = 'all'
+        elif tool == 'bbs_view':
+            curs.execute(db_change('select set_data from bbs_set where set_name = "bbs_view_acl" and set_id = ?'), [name])
         else:
             # tool == 'render'
             if i == 0:
@@ -2055,33 +2077,53 @@ def ip_pas(raw_ip, type_data = 0):
         get_ip = raw_ip
 
     curs.execute(db_change("select data from other where name = 'ip_view'"))
-    ip_view = curs.fetchall()
-    ip_view = ip_view[0][0] if ip_view else ''
+    db_data = curs.fetchall()
+    ip_view = db_data[0][0] if db_data else ''
     ip_view = '' if admin_check(1) == 1 else ip_view
+
+    curs.execute(db_change("select data from other where name = 'user_name_view'"))
+    db_data = curs.fetchall()
+    user_name_view = db_data[0][0] if db_data else ''
+    user_name_view = '' if admin_check(1) == 1 else user_name_view
     
     get_ip = list(set(get_ip))
     
     for raw_ip in get_ip:
         change_ip = 0
         is_this_ip = ip_or_user(raw_ip)
-        if is_this_ip != 0 and ip_view != '':
-            try:
-                ip = ipaddress.ip_address(raw_ip)
-                if type(ip) == ipaddress.IPv6Address:
-                    ip = ip.exploded
-                    ip = re.sub(r':([^:]*):([^:]*)$', ':*:*', ip)
+        if is_this_ip != 0:
+            # ip user
+            if ip_view != '':
+                try:
+                    ip = ipaddress.ip_address(raw_ip)
+                    if type(ip) == ipaddress.IPv6Address:
+                        ip = ip.exploded
+                        ip = re.sub(r':([^:]*):([^:]*)$', ':*:*', ip)
+                    else:
+                        ip = ip.exploded
+                        ip = re.sub(r'\.([^.]*)\.([^.]*)$', '.*.*', ip)
+                    
+                    # ip = hashlib.sha3_224(bytes(raw_ip, 'utf-8')).hexdigest()
+                    # ip = ip[0:4] + '-' + ip[4:8] + '-' + ip[8:12] + '-' + ip[12:16]
+
+                    change_ip = 1
+                except:
+                    ip = raw_ip
+            else:
+                ip = raw_ip
+        else:
+            # not ip user
+            if ip_view != '':
+                curs.execute(db_change("select data from user_set where id = ? and name = 'sub_user_name'"), [raw_ip])
+                db_data = curs.fetchall()
+                if db_data and db_data[0][0] != '':
+                    ip = db_data[0][0]
                 else:
-                    ip = ip.exploded
-                    ip = re.sub(r'\.([^.]*)\.([^.]*)$', '.*.*', ip)
-                
-                # ip = hashlib.sha3_224(bytes(raw_ip, 'utf-8')).hexdigest()
-                # ip = ip[0:4] + '-' + ip[4:8] + '-' + ip[8:12] + '-' + ip[12:16]
+                    ip = load_lang('member')
 
                 change_ip = 1
-            except:
+            else:
                 ip = raw_ip
-        else:     
-            ip = raw_ip
             
         if type_data == 0 and change_ip == 0:
             if is_this_ip == 0:

+ 0 - 2
route/tool/func_render_namumark.py

@@ -617,8 +617,6 @@ class class_do_render_namumark:
                 link_main = self.get_tool_data_restore(link_main, do_type = 'slash')
                 link_main = html.unescape(link_main)
 
-                print(link_main)
-
                 self.curs.execute(db_change("select set_data from data_set where doc_name = ? and set_name = 'last_edit'"), [link_main])
                 db_data = self.curs.fetchall()
                 if db_data:

+ 1 - 0
route/tool/func_tool.py

@@ -25,6 +25,7 @@ def db_change(data):
         data = data.replace('random()', 'rand()')
         data = data.replace('%', '%%')
         data = data.replace('?', '%s')
+        data = data.replace('collate nocase', 'collate utf8mb4_general_ci')
 
     return data
 

+ 10 - 5
route/topic.py

@@ -1,9 +1,6 @@
 from .tool.func import *
 from .api_topic import api_topic
 
-def topic_make(data, ip_first = ''):
-    data = ''
-
 def topic(topic_num = 0, do_type = '', doc_name = 'Test'):
     with get_db_connect() as conn:
         curs = conn.cursor()
@@ -186,14 +183,22 @@ def topic(topic_num = 0, do_type = '', doc_name = 'Test'):
             
             shortcut += '</div>'
 
+            top_topic = ''
+            json_data = json.loads(api_topic(int(topic_num), 'top', '', 'render').data)
+            top_topic += json_data['data'] if 'data' in json_data else ''
+            
+            main_topic = ''
+            json_data = json.loads(api_topic(int(topic_num), 'normal', '', 'render').data)
+            main_topic += json_data['data'] if 'data' in json_data else ''
+
             return easy_minify(flask.render_template(skin_check(),
                 imp = [name, wiki_set(), wiki_custom(), wiki_css(['(' + load_lang('discussion') + ')', 0])],
                 data = '''
                     ''' + shortcut + '''
                     <h2 id="topic_top_title">''' + html.escape(sub) + '''</h2>
                     
-                    <div id="top_topic"></div>
-                    <div id="main_topic"></div>
+                    <div id="top_topic">''' + top_topic + '''</div>
+                    <div id="main_topic">''' + main_topic + '''</div>
                     <div id="plus_topic"></div>
                     
                     <a href="/thread/''' + topic_num + '/tool">(' + load_lang('topic_tool') + ''')</a>

+ 8 - 1
route/user_setting.py

@@ -15,7 +15,8 @@ def user_setting():
                 auto_list = [
                     ['skin', flask.request.form.get('skin', '')], 
                     ['lang', flask.request.form.get('lang', '')],
-                    ['user_title', flask.request.form.get('user_title', '')]
+                    ['user_title', flask.request.form.get('user_title', '')],
+                    ['sub_user_name' , flask.request.form.get('sub_user_name', '')]
                 ]
 
                 twofa_on = flask.request.form.get('2fa', '')
@@ -96,6 +97,10 @@ def user_setting():
                 fa_data_pw = curs.fetchall()
                 fa_data_pw = load_lang('2fa_password_change') if fa_data_pw else load_lang('2fa_password')
 
+                curs.execute(db_change('select data from user_set where name = "sub_user_name" and id = ?'), [ip])
+                db_data = curs.fetchall()
+                sub_user_name = db_data[0][0] if db_data else ''
+
                 return easy_minify(flask.render_template(skin_check(),
                     imp = [load_lang('user_setting'), wiki_set(), wiki_custom(), wiki_css([0, 0])],
                     data = '''
@@ -127,6 +132,8 @@ def user_setting():
                             <select name="2fa" id="twofa_check_input">''' + fa_data_select + '''</select>
                             <hr class="main_hr">
                             <input type="password" name="2fa_pw" placeholder="''' + fa_data_pw + '''">
+                            <h2>''' + load_lang('sub_user_name') + '''</h2>
+                            <input name="sub_user_name" value="''' + html.escape(sub_user_name) + '''" placeholder="''' + load_lang('sub_user_name') + '''">
                             <hr class="main_hr">
                             <button type="submit">''' + load_lang('save') + '''</button>
                             ''' + http_warning() + '''

+ 1 - 1
route/give_acl.py → route/view_acl.py

@@ -1,6 +1,6 @@
 from .tool.func import *
 
-def give_acl_2(name):
+def view_acl(name):
     with get_db_connect() as conn:
         curs = conn.cursor()
 

+ 1 - 1
version.json

@@ -1,6 +1,6 @@
 {
     "beta" : {
-        "r_ver" : "v3.4.6-RC3-dev166",
+        "r_ver" : "v3.4.6-RC3-dev170",
         "c_ver" : "3500361",
         "s_ver" : "3500111"
     }

+ 11 - 1
views/main_css/css/main.css

@@ -93,6 +93,10 @@ summary {
     display: none;
 }
 
+.opennamu_comment_blind_admin {
+    background: gainsboro;
+}
+
 .opennamu_comment_scroll {
     max-height: 500px;
     
@@ -218,6 +222,9 @@ pre {
     background-color: #efefef;
     
     border: 1px solid #cecece;
+
+    font-size: small;
+    font-weight: initial;
 }
 
 .opennamu_popup_footnote {
@@ -232,6 +239,9 @@ pre {
     background-color: #efefef;
     
     border: 1px solid #cecece;
+
+    font-size: small;
+    font-weight: initial;
 }
 
 @media ( max-width: 768px ) {
@@ -255,7 +265,7 @@ hr {
 
 blockquote {
     padding: 15px 40px 15px 15px;
-    margin: 15px 0 0;
+    margin: 0;
 
     display: inline-block;
 

+ 3 - 6
views/main_css/js/route/render.js

@@ -121,7 +121,6 @@ function opennamu_do_render_html(name = '') {
 
 function opennamu_do_footnote_spread(set_name, load_name) {
     if(document.getElementById(set_name + '_load').style.display === 'none') {
-        console.log(set_name, load_name);
         document.getElementById(set_name).title = '';
         document.getElementById(set_name + '_load').innerHTML = '<a href="#' + load_name + '">(Go)</a> ' + document.getElementById(load_name + '_title').innerHTML;
         document.getElementById(set_name + '_load').style.display = "inline-block";
@@ -132,7 +131,6 @@ function opennamu_do_footnote_spread(set_name, load_name) {
 
 function opennamu_do_footnote_popover(set_name, load_name) {
     if(document.getElementById(set_name + '_load').style.display === 'none') {
-        console.log(set_name, load_name);
         document.getElementById(set_name).title = '';
         document.getElementById(set_name + '_load').innerHTML = '<a href="#' + load_name + '">(Go)</a> ' + document.getElementById(load_name + '_title').innerHTML;
         document.getElementById(set_name + '_load').style.display = "inline-block";
@@ -141,11 +139,10 @@ function opennamu_do_footnote_popover(set_name, load_name) {
         let screen_width = window.innerWidth;
         let left = document.getElementById(set_name).getBoundingClientRect().left;
         let left_org = document.getElementById(set_name + '_load').getBoundingClientRect().left;
-        let top = document.getElementById(set_name).getBoundingClientRect().top;
-        console.log(width, screen_width, left, left_org);
-        console.log(screen_width - (left + width));
+        let top = window.pageYOffset + document.getElementById(set_name).getBoundingClientRect().top;
+
+        document.getElementById(set_name + '_load').style.top = String(top) + "px";
         if(screen_width - (left + width) < 50) {
-            console.log("test");
             if(left > 350) {
                 document.getElementById(set_name + '_load').style.left = String(left - 300) + "px";
             } else {

+ 0 - 185
views/main_css/js/route/thread.js

@@ -1,185 +0,0 @@
-// 폐지하고 다시 SSR 방식으로 전환 예정
-function opennamu_do_thread_make(topic_num, type_do = 'top', some = '', where = 'top_topic') {
-    let url = '';
-    if(type_do === 'top') {
-        url = "/api/thread/" + topic_num + "/top";
-    } else if(type_do === 'main') {
-        url = "/api/thread/" + topic_num;
-    } else {
-        url = "/api/thread/" + topic_num + some;
-    }
-
-    let xhr = new XMLHttpRequest();
-    xhr.open("GET", url);
-    xhr.send();
-
-    xhr.onreadystatechange = function() {
-        if(this.readyState === 4 && this.status === 200) {
-            let data_t = JSON.parse(this.responseText);
-            
-            let start = 0;
-            let key_v = '/normal/1';
-            let admin = '';
-            let ip_first = '';
-            
-            let data_all = '';
-            let data_all_js = '';
-            
-            let count = 0;
-            for(let key in data_t) {
-                let data_a = '';
-                
-                if(start === 0) {
-                    admin = data_t['data_main']['admin'];
-                    ip_first = data_t['data_main']['ip_first'];
-                
-                    start = 1;
-                }
-                
-                if(key === 'data_main') {
-                    continue;
-                }
-                
-                key_v = '/normal/' + String(Number(key) + 1);
-                
-                let color_b = '';
-                let color_t = '';
-                
-                let ip = data_t[key]['ip_pas'];
-                let ip_o = data_t[key]['ip'];
-                let blind = data_t[key]['blind'];
-                let data_i_pas = data_t[key]['data_pas'][0];
-                let data_get_list = [];
-
-                if(data_i_pas === '') {
-                    data_i_pas = '<br>';
-                } else {
-                    let load_thread_regex = /&lt;topic_a&gt;((?:(?!&lt;\/topic_a&gt;).)+)&lt;\/topic_a&gt;/g;
-
-                    data_get_list = data_i_pas.match(load_thread_regex);
-
-                    data_i_pas = data_i_pas.replace(load_thread_regex, '<a href="$1">$1</a>');
-                    data_i_pas = data_i_pas.replace(/&lt;topic_call&gt;@((?:(?!&lt;\/topic_call&gt;).)+)&lt;\/topic_call&gt;/g, '<a href="/w/user:$1">@$1</a>');
-                }
-                
-                if(blind === 'O') {
-                    color_b = 'opennamu_comment_blind';
-                } else {
-                    color_b = 'opennamu_comment_blind_not';
-                }
-                
-                if(blind === 'O') {
-                    ip += ' <a href="/list/admin/auth_use/' + opennamu_do_url_encode('blind (code ' + topic_num + '#' + key) + '/1">(B)</a>';
-                    
-                    if(admin === '1') {
-                        ip += ' <a href="javascript:opennamu_do_open_comment(\'' + key + '\');">(O)</a>';
-                    }
-                }
-                
-                if(admin === '1' || blind !== 'O') {
-                    ip += ' <a href="/thread/' + topic_num + '/comment/' + key + '/tool">(T)</a>';
-                }
-                
-                if(type_do === 'top') {
-                    color_t = 'opennamu_comment_color_red';
-                } else if(blind === '1') {
-                    color_t = 'opennamu_comment_color_blue';
-                } else if(blind === 'O') {
-                    color_t = 'opennamu_comment_color_gray';
-                } else if(ip_o === ip_first) {
-                    color_t = 'opennamu_comment_color_green';
-                } else {
-                    color_t = 'opennamu_comment_color_default';
-                }
-                
-                data_a += '' + 
-                    '<table class="opennamu_comment">' + 
-                        '<tr>' + 
-                            '<td class="' + color_t + '">' + 
-                                '<a href="#thread_shortcut" id="' + key + '">#' + key + '</a> ' + 
-                                ip + 
-                                '<span style="float: right;">' + data_t[key]['date'] + '</span>' + 
-                            '</td>' + 
-                        '</tr>' + 
-                        '<tr>' + 
-                            '<td class="' + color_b + '" id="opennamu_comment_data_' + key + '">' + 
-                                '<div class="opennamu_comment_scroll">' + data_i_pas + '</div>' + 
-                            '</td>' + 
-                        '</tr>' +
-                    '</table>' + 
-                    '<hr class="main_hr">' + 
-                ''
-
-                document.getElementById(where).innerHTML += data_a;
-                
-                count += 1;
-                data_all_js += data_t[key]['data_pas'][1] + '\n';
-                
-                if(count > 100) {
-                    eval(data_all_js);
-                    
-                    count = 0;
-                    data_all_js = '';
-                }
-            }
-            
-            eval(data_all_js);
-            
-            if(type_do === 'top') {
-                opennamu_do_thread_make(topic_num, 'main', '', 'main_topic');
-            } else if(type_do === 'main') {
-                let data_url_v = window.location.hash.replace(/^#/, '');
-                if(data_url_v !== '') {
-                    if(document.getElementById(data_url_v)) {
-                        document.getElementById(data_url_v).focus();
-                    }
-                }
-                
-                opennamu_do_thread_make(topic_num, 're', key_v, where);
-            } else if(type_do === 're') {
-                setTimeout(function() {
-                    if(start === 0) {
-                        opennamu_do_thread_make(topic_num, 're', some, where);
-                    } else {
-                        opennamu_do_thread_make(topic_num, 're', key_v, where);
-                    }
-                }, 2000);
-            }
-        }
-    }
-}
-
-function opennamu_do_open_comment(key) {
-    let element_state = document.getElementById('opennamu_comment_data_' + key).style.display;
-    if(!element_state || element_state === 'none') {
-        document.getElementById('opennamu_comment_data_' + key).style.display = 'block';
-    } else {
-        document.getElementById('opennamu_comment_data_' + key).style.display = 'none';
-    }
-}
-
-if(window.location.pathname.match(/^\/(thread|thread_preview)\//)) {
-    let thread_num = window.location.pathname.match(/^\/(?:thread|thread_preview)\/([0-9]+)/)[1];
-
-    opennamu_do_thread_make(thread_num);
-} else if(window.location.pathname.match(/^\/topic\//)) {
-    for(let for_a = 0; document.getElementsByClassName('topic_pre')[for_a]; for_a++) {
-        let thread_num = document.getElementsByClassName('topic_pre')[for_a].id;
-        thread_num = thread_num.match(/^opennamu_thread_([0-9]+)/)[1];
-
-        opennamu_do_thread_make(thread_num, "list", "/normal/1", "opennamu_thread_" + thread_num);
-
-        let xhr = new XMLHttpRequest();
-        xhr.open("GET", "/api/thread/" + thread_num + "/length");
-        xhr.send();
-
-        xhr.onreadystatechange = function() {
-            if(this.readyState === 4 && this.status === 200) {
-                let thread_length = JSON.parse(this.responseText)['length'];
-                if(thread_length !== '1') {
-                    opennamu_do_thread_make(thread_num, "list", "/normal/" + thread_length, "opennamu_thread_back_" + thread_num);
-                }
-            }
-        }
-    }
-}

+ 4 - 0
views/ringo/index.html

@@ -57,6 +57,10 @@
                             <span class="iconify" data-icon="ic:baseline-how-to-vote" data-inline="true"></span>
                             {{'vote_list'|load_lang}}
                         </a>
+                        <a href="/bbs/main">
+                            <span class="iconify" data-icon="ic:outline-developer-board" data-inline="true"></span>
+                            {{'bbs_main'|load_lang}}
+                        </a>
                     </div>
                 </div>
                 <div class="top_cel" id="other_cel">

+ 5 - 0
views/tenshi/index.html

@@ -60,6 +60,11 @@
                                         <span class="iconify" data-icon="ic:baseline-how-to-vote" data-inline="true"></span>
                                         {{'vote_list'|load_lang}}
                                     </a>
+                                    <hr>
+                                    <a href="/bbs/main">
+                                        <span class="iconify" data-icon="ic:outline-developer-board" data-inline="true"></span>
+                                        {{'bbs_main'|load_lang}}
+                                    </a>
                                 </div>
                             </div>