Просмотр исходного кода

Merge pull request #1849 from openNAMU/dev

병렬스레드 지원 및 여러 기능 추가
잉여개발기 (SPDV) 2 лет назад
Родитель
Сommit
4d9150b2e3

+ 27 - 75
app.py

@@ -1,7 +1,8 @@
 # Init
 import os
 import re
-import ctypes
+import logging
+import shutil
 
 from route.tool.func import *
 from route import *
@@ -298,55 +299,40 @@ app.route('/extension_filter/del/<everything:name>', defaults = { 'tool' : 'del_
 app.route('/extension_filter/add', methods = ['POST', 'GET'], defaults = { 'tool' : 'plus_extension_filter' })(filter_inter_wiki_add)
 
 # Func-list
-# /list/document/old
 app.route('/list/document/old')(list_old_page)
 app.route('/list/document/old/<int:num>')(list_old_page)
 
-# /list/document/acl
 app.route('/list/document/acl')(list_acl)
 app.route('/list/document/acl/<int:arg_num>')(list_acl)
 
-# /list/document/need
 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('/list/document/long')(list_long_page)
 app.route('/list/document/long/<int:arg_num>')(list_long_page)
 
-# /list/document/short
 app.route('/list/document/short', defaults = { 'tool' : 'short_page' })(list_long_page)
 app.route('/list/document/short/<int:arg_num>', defaults = { 'tool' : 'short_page' })(list_long_page)
 
-# /list/file
 app.route('/list/file')(list_image_file)
 app.route('/list/file/<int:arg_num>')(list_image_file)
 
-# /list/admin
-# /list/admin/list
 app.route('/list/admin')(list_admin)
 
-# /list/admin/auth_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('/list/user')(list_user)
 app.route('/list/user/<int:arg_num>')(list_user)
 
-# /list/user/check
-@app.route('/check/<name>')
-def give_user_check(name = None):
-    return give_user_check_2(name)
-    
-# /list/user/check/delete
-@app.route('/check_delete', methods = ['POST', 'GET'])
-def give_user_check_delete():
-    return give_user_check_delete_2()
+app.route('/list/user/check/<name>')(list_user_check)
+app.route('/list/user/check/<name>/<do_type>')(list_user_check)
+app.route('/list/user/check/<name>/<do_type>/<int:arg_num>')(list_user_check)
+app.route('/list/user/check/<name>/<do_type>/<int:arg_num>/<plus_name>')(list_user_check)
+app.route('/list/user/check/delete/<name>/<ip>/<time>/<do_type>', methods = ['POST', 'GET'])(list_user_check_delete)
 
 # Func-auth
 # /auth/give
@@ -362,33 +348,23 @@ app.route('/auth/give/ban_regex/<everything:name>', methods = ['POST', 'GET'], d
 app.route('/auth/give/ban_multiple', methods = ['POST', 'GET'], defaults = { 'ban_type' : 'multiple' })(give_user_ban)
 
 # /auth/list
-@app.route('/admin_group')
-def list_admin_group():
-    return list_admin_group_2()
+app.route('/admin_group')(list_admin_group_2)
 
 # /auth/list/add/<name>
-@app.route('/admin_plus/<name>', methods = ['POST', 'GET'])
-def give_admin_groups(name = None):
-    return give_admin_groups_2(name)
+app.route('/admin_plus/<name>', methods = ['POST', 'GET'])(give_admin_groups_2)
 
 # /auth/list/delete/<name>
-@app.route('/delete_admin_group/<name>', methods = ['POST', 'GET'])
-def give_delete_admin_group(name = None):
-    return give_delete_admin_group_2(name)
+app.route('/delete_admin_group/<name>', methods = ['POST', 'GET'])(give_delete_admin_group_2)
 
 app.route('/auth/give/fix/<user_name>', methods = ['POST', 'GET'])(give_user_fix)
 
-@app.route('/app_submit', methods = ['POST', 'GET'])
-def recent_app_submit():
-    return recent_app_submit_2()
+app.route('/app_submit', methods = ['POST', 'GET'])(recent_app_submit_2)
 
 # /auth/history
 # ongoing 반영 필요
-@app.route('/block_log')
-@app.route('/block_log/<regex("user"):tool>/<name>')
-@app.route('/block_log/<regex("admin"):tool>/<name>')
-def recent_block(name = 'Test', tool = 'all'):
-    return recent_block_2(name, tool)
+app.route('/block_log')(recent_block_2)
+app.route('/block_log/<regex("user"):tool>/<name>')(recent_block_2)
+app.route('/block_log/<regex("admin"):tool>/<name>')(recent_block_2)
 
 # Func-history
 app.route('/recent_change')(recent_change)
@@ -503,15 +479,9 @@ app.route('/star_doc', defaults = { 'tool' : 'star_doc' })(user_watch_list)
 app.route('/star_doc/<everything:name>', defaults = { 'tool' : 'star_doc' })(user_watch_list_name)
 
 # 개편 보류중 S
-@app.route('/change/email', methods = ['POST', 'GET'])
-def user_setting_email():
-    return user_setting_email_2()
-
+app.route('/change/email', methods = ['POST', 'GET'])(user_setting_email_2)
 app.route('/change/email/delete')(user_setting_email_delete)
-
-@app.route('/change/email/check', methods = ['POST', 'GET'])
-def user_setting_email_check():
-    return user_setting_email_check_2()
+app.route('/change/email/check', methods = ['POST', 'GET'])(user_setting_email_check_2)
 # 개편 보류중 E
 
 # Func-login
@@ -521,29 +491,12 @@ def user_setting_email_check():
 # register -> register/email -> regiter/email/check with reg_id
 # pass_find -> pass_find/email with find_id
 
-@app.route('/login', methods = ['POST', 'GET'])
-def login_login():
-    return login_login_2()
-
-@app.route('/login/2fa', methods = ['POST', 'GET'])
-def login_login_2fa():
-    return login_login_2fa_2()
-
-@app.route('/register', methods = ['POST', 'GET'])
-def login_register():
-    return login_register_2()
-
-@app.route('/register/email', methods = ['POST', 'GET'])
-def login_register_email():
-    return login_register_email_2()
-
-@app.route('/register/email/check', methods = ['POST', 'GET'])
-def login_register_email_check():
-    return login_register_email_check_2()
-
-@app.route('/register/submit', methods = ['POST', 'GET'])
-def login_register_submit():
-    return login_register_submit_2()
+app.route('/login', methods = ['POST', 'GET'])(login_login_2)
+app.route('/login/2fa', methods = ['POST', 'GET'])(login_login_2fa_2)
+app.route('/register', methods = ['POST', 'GET'])(login_register_2)
+app.route('/register/email', methods = ['POST', 'GET'])(login_register_email_2)
+app.route('/register/email/check', methods = ['POST', 'GET'])(login_register_email_check_2)
+app.route('/register/submit', methods = ['POST', 'GET'])(login_register_submit_2)
 
 app.route('/login/find')(login_find)
 app.route('/login/find/key', methods = ['POST', 'GET'])(login_find_key)
@@ -568,11 +521,11 @@ app.route('/bbs/make', methods = ['POST', 'GET'])(bbs_make)
 # app.route('/bbs/main/set')
 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/edit/<int:bbs_num>', methods = ['POST', 'GET'])(bbs_w_edit)
+app.route('/bbs/edit/preview/<int:bbs_num>', methods = ['POST', 'GET'], defaults = { 'do_type' : 'preview' })(bbs_w_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/edit/<int:bbs_num>/<int:post_num>', methods = ['POST', 'GET'])(bbs_w_edit)
+app.route('/bbs/edit/preview/<int:bbs_num>/<int:post_num>', methods = ['POST', 'GET'], defaults = { 'do_type' : 'preview' })(bbs_w_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>')
 
@@ -689,6 +642,5 @@ if __name__ == "__main__":
         app,
         host = server_set['host'],
         port = int(server_set['port']),
-        threads = 1,
         clear_untrusted_proxy_headers = True
-    )
+    )

+ 1 - 0
emergency_tool.py

@@ -4,6 +4,7 @@ import os
 import platform
 import urllib
 import zipfile
+import urllib.request
 
 from route.tool.func import *
 

+ 2 - 0
requirements.txt

@@ -1,3 +1,5 @@
+pip
+
 flask
 waitress
 

+ 3 - 3
route/__init__.py

@@ -15,7 +15,7 @@ from route.api_w import api_w
 from route.api_bbs_w_post import api_bbs_w_post
 from route.api_bbs_w_comment import api_bbs_w_comment
 
-from route.bbs_edit import bbs_edit
+from route.bbs_w_edit import bbs_w_edit
 from route.bbs_main import bbs_main
 from route.bbs_make import bbs_make
 from route.bbs_w import bbs_w
@@ -42,8 +42,6 @@ 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
@@ -56,6 +54,8 @@ 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.list_user_check import list_user_check
+from route.list_user_check_delete import list_user_check_delete
 
 from route.login_find import login_find
 from route.login_find_email import login_find_email

+ 6 - 8
route/api_bbs_w_comment.py

@@ -1,20 +1,18 @@
 from .tool.func import *
 
-def api_bbs_w_comment(sub_code : str = '') -> typing.Union[str, flask.Response, werkzeug.wrappers.response.Response]:
-    conn : typing.Union[sqlite3.Connection, pymysql.connections.Connection]
+def api_bbs_w_comment(sub_code = ''):
     with get_db_connect() as conn:
-        curs : typing.Union[sqlite3.Cursor, pymysql.cursors.Cursor] = conn.cursor()
+        curs = conn.cursor()
 
         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'), [sub_code])
-        db_data : typing.Optional[typing.List[typing.Tuple[str, str, str]]] = curs.fetchall()
+        db_data = curs.fetchall()
         if not db_data:
             return flask.jsonify({})
         else:
-            temp_id : str = ''
-            temp_dict : dict[str, str] = {}
-            temp_list : typing.List[dict[str, str]] = []
+            temp_id = ''
+            temp_dict = {}
+            temp_list = []
 
-            for_a : typing.Tuple[str, str, str]
             for for_a in db_data:
                 if temp_id != for_a[2]:
                     if temp_dict != {}:

+ 6 - 8
route/api_bbs_w_post.py

@@ -1,23 +1,21 @@
 from .tool.func import *
 
-def api_bbs_w_post(sub_code : str = '') -> typing.Union[str, flask.Response, werkzeug.wrappers.response.Response]:
-    sub_code_split : typing.List[str] = sub_code.split('-')
+def api_bbs_w_post(sub_code = ''):
+    sub_code_split = sub_code.split('-')
     if len(sub_code_split) < 2:
         sub_code_split = ['', '']
 
-    conn : typing.Union[sqlite3.Connection, pymysql.connections.Connection]
     with get_db_connect() as conn:
-        curs : typing.Union[sqlite3.Cursor, pymysql.cursors.Cursor] = conn.cursor()
+        curs = conn.cursor()
 
         curs.execute(db_change('select set_name, set_data, set_code from bbs_data where set_id = ? and set_code = ?'), [sub_code_split[0], sub_code_split[1]])
-        db_data : typing.Optional[typing.List[typing.Tuple[str, str, str]]] = curs.fetchall()
+        db_data = curs.fetchall()
         if not db_data:
             return flask.jsonify({})
         else:
-            temp_id : str = ''
-            temp_dict : dict[str, str] = {}
+            temp_id = ''
+            temp_dict = {}
 
-            for_a : typing.Tuple[str, str, str]
             for for_a in db_data:
                 if temp_id != for_a[2]:
                     temp_id = for_a[2]

+ 2 - 0
route/api_skin_info.py

@@ -1,3 +1,5 @@
+import urllib.request
+
 from .tool.func import *
 
 def api_skin_info(name = ''):

+ 108 - 2
route/api_topic.py

@@ -1,5 +1,111 @@
 from .tool.func import *
-from .bbs_w_post import bbs_w_post_make_thread
+
+def api_topic_thread_make(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 api_topic_thread_pre_render(curs, data, num, ip, topic_num = '', name = '', sub = '', do_type = 'thread'):
+    # 이거 좀 엉성해서 언젠간 손 보고 싶음
+
+    call_thread_regex = r"( |\n|^)(?:#([0-9]+)(?:-([0-9]+))?)( |\n|$)"
+    call_thread_count = len(re.findall(call_thread_regex, data)) * 3
+    while 1:
+        rd_data = re.search(call_thread_regex, data)
+        if call_thread_count < 0:
+            break
+        elif not rd_data:
+            break
+        else:
+            rd_data = rd_data.groups()
+
+            view_data = rd_data[1]
+            send_topic_num = topic_num
+            if rd_data[2]:
+                view_data += '-' + rd_data[2]
+                if do_type == 'thread':
+                    send_topic_num = rd_data[2]
+                else:
+                    set_id = topic_num.split('-')
+
+                    send_topic_num = set_id[0] + '-' + rd_data[2]
+                    view_data += '-' + set_id[0]
+
+            if do_type == 'thread':
+                curs.execute(db_change("select ip from topic where code = ? and id = ?"), [send_topic_num, rd_data[1]])
+            else:
+                if rd_data[1] == '0':
+                    set_id = send_topic_num.split('-')
+                    set_id = ['', ''] if len(set_id) < 2 else set_id
+
+                    curs.execute(db_change('select set_data from bbs_data where set_name = "user_id" and set_id = ? and set_code = ?'), [set_id[0], set_id[1]])
+                else:
+                    curs.execute(db_change('select set_data from bbs_data where set_name = "comment_user_id" and set_id = ? and set_code = ?'), [send_topic_num, rd_data[1]])
+
+            ip_data = curs.fetchall()
+            if ip_data and ip_or_user(ip_data[0][0]) == 0:
+                if do_type == 'thread':
+                    add_alarm(ip_data[0][0], ip, '<a href="/thread/' + topic_num + '#' + num + '">' + html.escape(name) + ' - ' + html.escape(sub) + '#' + num + '</a>')
+                else:
+                    set_id = topic_num.split('-')
+                    set_id = ['', ''] if len(set_id) < 2 else set_id
+
+                    add_alarm(ip_data[0][0], ip, 'BBS <a href="/bbs/w/' + set_id[0] + '/' + set_id[1] + '#' + num + '">' + html.escape(name) + ' - ' + html.escape(sub) + '#' + num + '</a>')
+
+            data = re.sub(call_thread_regex, rd_data[0] + '<topic_a_' + do_type + '>#' + view_data + '</topic_a_' + do_type + '>' + rd_data[3], data, 1)
+
+        call_thread_count -= 1
+
+    call_user_regex = r"( |\n|^)(?:@([^ \n]+))( |\n|$)"
+    call_user_count = len(re.findall(call_user_regex, data)) * 3
+    while 1:
+        rd_data = re.search(call_user_regex, data)
+        if call_user_count < 0:
+            break
+        elif not rd_data:
+            break
+        else:
+            rd_data = rd_data.groups()
+
+            curs.execute(db_change("select ip from history where ip = ? limit 1"), [rd_data[1]])
+            ip_data = curs.fetchall()
+            if not ip_data:
+                curs.execute(db_change("select ip from topic where ip = ? limit 1"), [rd_data[1]])
+                ip_data = curs.fetchall()
+
+            if ip_data and ip_or_user(ip_data[0][0]) == 0:
+                if do_type == 'thread':
+                    add_alarm(ip_data[0][0], ip, '<a href="/thread/' + topic_num + '#' + num + '">' + html.escape(name) + ' - ' + html.escape(sub) + '#' + num + '</a>')
+                else:
+                    set_id = topic_num.split('-')
+                    add_alarm(ip_data[0][0], ip, 'BBS <a href="/bbs/w/' + set_id[0] + '/' + set_id[1] + '#' + num + '">' + html.escape(name) + ' - ' + html.escape(sub) + '#' + num + '</a>')
+
+            data = re.sub(call_user_regex, rd_data[0] + '<topic_call>@' + rd_data[1] + '</topic_call>' + rd_data[2], data, 1)
+
+        call_user_count -= 1
+
+    return data
 
 def api_topic(topic_num = 1, tool = 'normal', num = '', render = ''):
     with get_db_connect() as conn:
@@ -77,7 +183,7 @@ def api_topic(topic_num = 1, tool = 'normal', num = '', render = ''):
                                 else:
                                     color = 'default'
 
-                            data_r += bbs_w_post_make_thread(
+                            data_r += api_topic_thread_make(
                                 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] + '<script>' + for_a["data_pas"][1] + '</script>',

+ 5 - 40
route/bbs_edit.py → route/bbs_w_edit.py

@@ -1,8 +1,9 @@
 from .tool.func import *
 
 from .api_bbs_w_post import api_bbs_w_post
+from .edit import edit_editor
 
-def bbs_edit(bbs_num = '', post_num = '', do_type = ''):
+def bbs_w_edit(bbs_num = '', post_num = '', do_type = ''):
     with get_db_connect() as conn:
         curs = conn.cursor()
 
@@ -110,31 +111,6 @@ def bbs_edit(bbs_num = '', post_num = '', do_type = ''):
                 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">'
@@ -146,17 +122,12 @@ def bbs_edit(bbs_num = '', post_num = '', do_type = ''):
     
             return easy_minify(flask.render_template(skin_check(), 
                 imp = [bbs_title, 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>
-                        
+                data =  editor_top_text + '''
+                    <form method="post">                        
                         <input placeholder="''' + load_lang('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>
+                        ''' + edit_editor(curs, ip, data) + '''
                         <hr class="main_hr">
                         
                         ''' + captcha_get() + ip_warning() + '''
@@ -166,12 +137,6 @@ def bbs_edit(bbs_num = '', post_num = '', do_type = ''):
                     
                         <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>
 
                         ''' + render_simple_set('''
                             <hr class="main_hr">

+ 54 - 90
route/bbs_w_post.py

@@ -2,61 +2,37 @@ from .tool.func import *
 
 from .api_bbs_w_post import api_bbs_w_post
 from .api_bbs_w_comment import api_bbs_w_comment
+from .api_topic import api_topic_thread_make, api_topic_thread_pre_render
 
-def bbs_w_post_make_thread(user_id : str, date : str, data : str, code : str, color : str = '', blind : str = '', add_style : str = '') -> str:
-    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_comment(user_id : str, sub_code : str, comment_num : str, bbs_num_str : str, post_num_str : str) -> typing.Tuple[str, str, int, int]:
-    comment_data : str = ''
-    comment_select : str = ''
-
-    comment_count : int = 0
-    comment_add_count : int = 0
-
-    thread_data : typing.List[dict[str, str]] = json.loads(api_bbs_w_comment(sub_code).data)
+from .edit import edit_editor
+
+def bbs_w_post_comment(user_id, sub_code, comment_num, bbs_num_str, post_num_str):
+    comment_data = ''
+    comment_select = ''
+
+    comment_count = 0
+    comment_add_count = 0
+
+    thread_data = json.loads(api_bbs_w_comment(sub_code).data)
     
     comment_count += len(thread_data)
     comment_add_count += comment_count
 
-    temp_dict : dict[str, str]
     for temp_dict in thread_data:
-        color : str = 'default'
+        color = 'default'
         if user_id == temp_dict['comment_user_id']:
             color = 'green'
 
-        sub_code_check : str = re.sub(r'^[0-9]+-[0-9]+-', '', sub_code + '-' + temp_dict['code'])
-        margin_count : int = sub_code_check.count('-')
+        sub_code_check = re.sub(r'^[0-9]+-[0-9]+-', '', sub_code + '-' + temp_dict['code'])
+        margin_count = sub_code_check.count('-')
 
-        date : str = ''
+        date = ''
         date += '<a href="javascript:opennamu_change_comment(\'' + sub_code_check + '\');">(' + load_lang('comment') + ')</a> '
         date += '<a href="/bbs/w/' + bbs_num_str + '/' + post_num_str + '/comment/' + sub_code_check + '/tool">(' + load_lang('tool') + ')</a> '
         date += temp_dict['comment_date']
 
         comment_data += '<span style="padding-left: 20px;"></span>' * margin_count
-        comment_data += bbs_w_post_make_thread(
+        comment_data += api_topic_thread_make(
             ip_pas(temp_dict['comment_user_id']),
             date,
             render_set(
@@ -68,14 +44,14 @@ def bbs_w_post_comment(user_id : str, sub_code : str, comment_num : str, bbs_num
             add_style = 'width: calc(100% - ' + str(margin_count * 20) + 'px);'
         )
 
-        comment_default : str = ''
+        comment_default = ''
         if comment_num == sub_code_check:
             comment_default = 'selected'
 
         comment_select += '<option value="' + sub_code_check + '" ' + comment_default + '>' + sub_code_check + '</option>'
         comment_data += '<hr class="main_hr">'
 
-        temp_data : typing.Tuple[str, str, int, int] = bbs_w_post_comment(user_id, sub_code + '-' + temp_dict['code'], comment_num, bbs_num_str, post_num_str)
+        temp_data = bbs_w_post_comment(user_id, sub_code + '-' + temp_dict['code'], comment_num, bbs_num_str, post_num_str)
 
         comment_data += temp_data[0]
         comment_select += temp_data[1]
@@ -83,40 +59,28 @@ def bbs_w_post_comment(user_id : str, sub_code : str, comment_num : str, bbs_num
 
     return (comment_data, comment_select, comment_count, comment_add_count)
 
-def bbs_w_post(bbs_num : typing.Union[int, str] = '', post_num : typing.Union[int, str] = '', do_type : str = '') -> typing.Union[str, flask.Response, werkzeug.wrappers.response.Response]:
-    conn : typing.Union[sqlite3.Connection, pymysql.connections.Connection]
+def bbs_w_post(bbs_num = '', post_num = '', do_type = ''):
     with get_db_connect() as conn:
-        curs : typing.Union[sqlite3.Cursor, pymysql.cursors.Cursor] = conn.cursor()
+        curs = conn.cursor()
 
         curs.execute(db_change('select set_data from bbs_set where set_id = ? and set_name = "bbs_name"'), [bbs_num])
-        db_data_3 : typing.Optional[typing.List[typing.Tuple[str]]] = curs.fetchall()
+        db_data_3 = curs.fetchall()
         if not db_data_3:
             return redirect('/bbs/main')
         
-        bbs_name : str = db_data_3[0][0]
-
-        bbs_num_str : str = str(bbs_num)
-        post_num_str : str = str(post_num)
-        bbs_comment_acl : int = acl_check(bbs_num_str, 'bbs_comment')
-        ip : str = ip_check()
-
-        set_id : str
-        text : str
-        data_preview : str
-        user_id : str
-        bbs_comment_form : str
-        id_data : str
-        data : str
-        date : str
-        temp_dict : dict[str, str]
-        new_id_data : str
+        bbs_name = db_data_3[0][0]
+
+        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()
 
         temp_dict = json.loads(api_bbs_w_post(bbs_num_str + '-' + post_num_str).data)
         if temp_dict == {}:
             return redirect('/bbs/main')
         
         curs.execute(db_change('select set_data from bbs_set where set_id = ? and set_name = "bbs_type"'), [bbs_num])
-        db_data_2 : typing.Optional[typing.List[typing.Tuple[str]]] = curs.fetchall()
+        db_data_2 = curs.fetchall()
         if not db_data_2:
             return redirect('/bbs/main')
         elif db_data_2[0][0] == 'thread':
@@ -132,7 +96,7 @@ def bbs_w_post(bbs_num : typing.Union[int, str] = '', post_num : typing.Union[in
                 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_4 : typing.Optional[typing.List[typing.Tuple[str]]] = curs.fetchall()
+                db_data_4 = curs.fetchall()
                 id_data = str(int(db_data_4[0][0]) + 1) if db_data_4 else '1'
 
                 data = flask.request.form.get('content', '')
@@ -141,7 +105,7 @@ def bbs_w_post(bbs_num : typing.Union[int, str] = '', post_num : typing.Union[in
                     return redirect('/bbs/w/' + bbs_num_str + '/' + post_num_str)
                 
                 data = data.replace('\r', '')
-                data = get_thread_pre_render(data, id_data, ip, set_id, bbs_name, temp_dict['title'], 'post')
+                data = api_topic_thread_pre_render(curs, data, id_data, ip, set_id, bbs_name, temp_dict['title'], 'post')
                 
                 date = get_time()
 
@@ -176,7 +140,7 @@ def bbs_w_post(bbs_num : typing.Union[int, str] = '', post_num : typing.Union[in
 
                 data = ''
                 data += '<h2>' + html.escape(temp_dict['title']) + '</h2>'
-                data += bbs_w_post_make_thread(
+                data += api_topic_thread_make(
                     ip_pas(temp_dict['user_id']),
                     date,
                     render_set(
@@ -184,15 +148,15 @@ def bbs_w_post(bbs_num : typing.Union[int, str] = '', post_num : typing.Union[in
                         data_type = 'thread',
                         data_in = 'bbs'
                     ),
-                    '1',
+                    '0',
                     color = 'green'
                 )
                 data += '<hr class="main_hr">'
 
                 user_id = temp_dict['user_id']
-                count : int = 1
+                count = 0
 
-                thread_data : typing.List[dict[str, str]] = json.loads(api_bbs_w_comment(bbs_num_str + '-' + post_num_str).data)
+                thread_data = json.loads(api_bbs_w_comment(bbs_num_str + '-' + post_num_str).data)
                 for temp_dict in thread_data:
                     count += 1
                     if user_id == temp_dict['comment_user_id']:
@@ -204,7 +168,7 @@ def bbs_w_post(bbs_num : typing.Union[int, str] = '', post_num : typing.Union[in
                     date += '<a href="/bbs/w/' + bbs_num_str + '/' + post_num_str + '/comment/' + str(count) + '/tool">(' + load_lang('tool') + ')</a> '
                     date += temp_dict['comment_date']
 
-                    data += bbs_w_post_make_thread(
+                    data += api_topic_thread_make(
                         ip_pas(temp_dict['comment_user_id']),
                         date,
                         render_set(
@@ -220,13 +184,13 @@ def bbs_w_post(bbs_num : typing.Union[int, str] = '', post_num : typing.Union[in
                 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>
+                        ''' + edit_editor(curs, ip, text, 'thread') + '''
                         <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>
+                        <button id="opennamu_save_button" formaction="/bbs/w/''' + bbs_num_str + '''/''' + post_num_str + '''" type="submit" onclick="do_monaco_to_textarea(); do_stop_exit_release();">''' + load_lang('send') + '''</button>
+                        <button id="opennamu_preview_button" formaction="/bbs/w/preview/''' + bbs_num_str + '''/''' + post_num_str + '''#opennamu_edit_textarea" type="submit" onclick="do_monaco_to_textarea(); do_stop_exit_release();">''' + load_lang('preview') + '''</button>
                         <hr class="main_hr">
                     '''
 
@@ -253,16 +217,16 @@ def bbs_w_post(bbs_num : typing.Union[int, str] = '', post_num : typing.Union[in
                 else:
                     captcha_post('', 0)
                 
-                select : str = flask.request.form.get('comment_select', '0')
+                select = flask.request.form.get('comment_select', '0')
                 select = '' if select == '0' else select
 
-                comment_user_name : str = ''
+                comment_user_name = ''
 
                 if select != '':
-                    select_split : typing.List[str] = select.split('-')
+                    select_split = select.split('-')
                     if len(select_split) < 2:
                         curs.execute(db_change('select set_data from bbs_data where set_name = "comment_user_id" and set_id = ? and set_code = ? limit 1'), [bbs_num_str + '-' + post_num_str, select_split[0]])    
-                        db_data_6 : typing.Optional[typing.List[typing.Tuple[str]]] = curs.fetchall()
+                        db_data_6 = curs.fetchall()
                         if not db_data_6:
                             # re_error로 변경 예정
                             return redirect('/bbs/w/' + bbs_num_str + '/' + post_num_str)
@@ -271,7 +235,7 @@ def bbs_w_post(bbs_num : typing.Union[int, str] = '', post_num : typing.Union[in
                             comment_user_name = db_data_6[0][0]
                     else:
                         curs.execute(db_change('select set_data from bbs_data where set_name = "comment_user_id" and set_id = ? and set_code = ? limit 1'), [bbs_num_str + '-' + post_num_str + '-' + '-'.join(select_split[0:len(select_split) - 1]), select_split[len(select_split) - 1]])
-                        db_data_7 : typing.Optional[typing.List[typing.Tuple[str]]] = curs.fetchall()
+                        db_data_7 = curs.fetchall()
                         if not db_data_7:
                             return redirect('/bbs/w/' + bbs_num_str + '/' + post_num_str)
                         else:
@@ -281,7 +245,7 @@ def bbs_w_post(bbs_num : typing.Union[int, str] = '', post_num : typing.Union[in
                     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 limit 1'), [set_id])
-                db_data_5 : typing.Optional[typing.List[typing.Tuple[str]]] = curs.fetchall()
+                db_data_5 = curs.fetchall()
                 id_data = str(int(db_data_5[0][0]) + 1) if db_data_5 else '1'
 
                 data = flask.request.form.get('content', '')
@@ -314,7 +278,7 @@ def bbs_w_post(bbs_num : typing.Union[int, str] = '', post_num : typing.Union[in
                     return re_error('/ban')
                     
                 text = ''
-                comment_num : str = ''
+                comment_num = ''
                 data_preview = ''
                 if do_type == 'preview':
                     text = flask.request.form.get('content', '')
@@ -334,7 +298,7 @@ def bbs_w_post(bbs_num : typing.Union[int, str] = '', post_num : typing.Union[in
 
                 data = ''
                 data += '<h2>' + html.escape(temp_dict['title']) + '</h2>'
-                data += bbs_w_post_make_thread(
+                data += api_topic_thread_make(
                     ip_pas(temp_dict['user_id']),
                     date,
                     render_set(
@@ -346,15 +310,15 @@ def bbs_w_post(bbs_num : typing.Union[int, str] = '', post_num : typing.Union[in
                 )
 
                 user_id = temp_dict['user_id']
-                comment_data : str = ''
+                comment_data = ''
 
-                comment_select : str = '<select id="opennamu_comment_select" name="comment_select">'
+                comment_select = '<select id="opennamu_comment_select" name="comment_select">'
                 comment_select += '<option value="0">' + load_lang('normal') + '</option>'
 
-                comment_count : int = 0
-                comment_add_count : int = 0
+                comment_count = 0
+                comment_add_count = 0
 
-                temp_data : typing.Tuple[str, str, int, int] = bbs_w_post_comment(user_id, bbs_num_str + '-' + post_num_str, comment_num, bbs_num_str, post_num_str)
+                temp_data = bbs_w_post_comment(user_id, bbs_num_str + '-' + post_num_str, comment_num, bbs_num_str, post_num_str)
 
                 comment_data += temp_data[0]
                 comment_select += temp_data[1]
@@ -379,13 +343,13 @@ def bbs_w_post(bbs_num : typing.Union[int, str] = '', post_num : typing.Union[in
                         ''' + comment_select + ''' <a href="javascript:opennamu_return_comment();">(R)</a>
                         <hr class="main_hr">
                         
-                        <textarea name="content" id="opennamu_edit_textarea" class="opennamu_textarea_100">''' + html.escape(text) + '''</textarea>
+                        ''' + edit_editor(curs, ip, text, 'thread') + '''
                         <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>
+                        <button id="opennamu_save_button" formaction="/bbs/w/''' + bbs_num_str + '''/''' + post_num_str + '''" type="submit" onclick="do_monaco_to_textarea(); do_stop_exit_release();">''' + load_lang('send') + '''</button>
+                        <button id="opennamu_preview_button" formaction="/bbs/w/preview/''' + bbs_num_str + '''/''' + post_num_str + '''#opennamu_edit_textarea" type="submit" onclick="do_monaco_to_textarea(); do_stop_exit_release();">''' + load_lang('preview') + '''</button>
                         <hr class="main_hr">
                     '''
 

+ 60 - 55
route/edit.py

@@ -1,5 +1,8 @@
+import multiprocessing
+
 from .tool.func import *
 
+
 def edit_render_set(name, content):
     render_set(
         doc_name = name,
@@ -19,6 +22,57 @@ def edit_timeout(func, args = (), timeout = 3):
         pool.close()
         pool.join()
         return 0
+        
+def edit_editor(curs, ip, data_main = '', do_type = 'edit'):
+    monaco_editor_top = ''
+    editor_display = ''
+    add_get_file = ''
+    monaco_display = ''
+
+    curs.execute(db_change('select data from other where name = "edit_help"'))
+    sql_d = curs.fetchall()
+    p_text = html.escape(sql_d[0][0]) if sql_d and sql_d[0][0] != '' else load_lang('default_edit_help')
+    
+    monaco_on = get_main_skin_set(curs, flask.session, 'main_css_monaco', ip)
+    if monaco_on == 'use':
+        editor_display = 'style="display: none;"'
+        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>
+        '''
+
+        monaco_editor_top = '<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:
+        monaco_display = 'style="display: none;"'
+        add_script = 'opennamu_edit_turn_off_monaco();'
+
+    if do_type == 'edit':
+        textarea_size = 'opennamu_textarea_500'
+    else:
+        textarea_size = 'opennamu_textarea_100'
+
+    return add_get_file + '''
+        <textarea style="display: none;" id="opennamu_edit_origin" name="doc_data_org">''' + html.escape(data_main) + '''</textarea>
+        <div>''' + monaco_editor_top + ' ' + edit_button('opennamu_edit_textarea', 'opennamu_monaco_editor') + '''</div>
+        
+        <div id="opennamu_monaco_editor" class="''' + textarea_size + '''" ''' + monaco_display + '''></div>
+        <textarea id="opennamu_edit_textarea" ''' + editor_display + ''' class="''' + textarea_size + '''" name="content" placeholder="''' + p_text + '''">''' + html.escape(data_main) + '''</textarea>
+        <hr class="main_hr">
+        <script>
+            do_stop_exit();
+            do_paste_image('opennamu_edit_textarea', 'opennamu_monaco_editor');
+            ''' + add_script + '''
+        </script>
+    '''
 
 def edit(name = 'Test', section = 0, do_type = ''):
     with get_db_connect() as conn:
@@ -98,15 +152,9 @@ def edit(name = 'Test', section = 0, do_type = ''):
             db_data_2 = curs.fetchall()
             db_data_2 = '' if not db_data_2 else number_check(db_data_2[0][0])
 
-            try:
-                if db_data_2 != '':
-                    timeout = edit_timeout(edit_render_set, (name, content), timeout = int(db_data_2))
-                else:
-                    timeout = 0
-            except Exception as e:
-                print('multiprocessing error : ')
-                print(e)
-
+            if db_data_2 != '' and platform.system() == 'Linux':
+                timeout = edit_timeout(edit_render_set, (name, content), timeout = int(db_data_2))
+            else:
                 timeout = 0
 
             if timeout == 1:
@@ -256,58 +304,21 @@ def edit(name = 'Test', section = 0, do_type = ''):
     
             editor_top_text += '<a href="/edit_filter">(' + load_lang('edit_filter_rule') + ')</a>'
     
-            curs.execute(db_change('select data from other where name = "edit_help"'))
-            sql_d = curs.fetchall()
-            p_text = html.escape(sql_d[0][0]) if sql_d and sql_d[0][0] != '' else load_lang('default_edit_help')
-            
-            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">'
 
             sub_menu = ' (' + str(section) + ')' if section != '' else ''
-    
+
             return easy_minify(flask.render_template(skin_check(), 
                 imp = [name, wiki_set(), wiki_custom(), wiki_css(['(' + load_lang('edit') + ')' + sub_menu, 0])],
-                data =  editor_top_text + add_get_file + '''
-                    <script>
-                        
-                    </script>
+                data = editor_top_text + '''
                     <form method="post">
-                        <textarea style="display: none;" id="opennamu_edit_origin" name="doc_data_org">''' + html.escape(data_section) + '''</textarea>
                         <textarea style="display: none;" name="doc_section_data_where">''' + data_section_where + '''</textarea>
                         <input style="display: none;" name="doc_section_edit_apply" value="''' + doc_section_edit_apply + '''">
 
                         <input style="display: none;" name="ver" value="''' + doc_ver + '''">
                         
-                        <div>''' + edit_button('opennamu_edit_textarea', 'opennamu_monaco_editor') + '''</div>
-                        
-                        <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" placeholder="''' + p_text + '''">''' + html.escape(data_section) + '''</textarea>
-                        <hr class="main_hr">
+                        ''' + edit_editor(curs, ip, data_section) + '''
 
                         <input placeholder="''' + load_lang('why') + '''" name="send">
                         <hr class="main_hr">
@@ -320,12 +331,6 @@ def edit(name = 'Test', section = 0, do_type = ''):
                     
                     <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 = [
                     ['w/' + url_pas(name), load_lang('return')],

+ 8 - 11
route/edit_delete_file.py

@@ -2,27 +2,24 @@ from .tool.func import *
 
 from .edit_delete import edit_delete
 
-# 처음으로 차세대 코드 방법론 적용
-# 앞으로 다 이렇게 작성할 예정
-def edit_delete_file(name : str = 'test.jpg') -> typing.Union[str, flask.Response, werkzeug.wrappers.response.Response]:
-    conn : typing.Union[sqlite3.Connection, pymysql.connections.Connection]
+def edit_delete_file(name = 'test.jpg'):
     with get_db_connect() as conn:
-        curs : typing.Union[sqlite3.Cursor, pymysql.cursors.Cursor] = conn.cursor()
+        curs = conn.cursor()
 
-        ip : str = ip_check()
+        ip = ip_check()
         if admin_check() == 0:
             return re_error('/ban')
 
-        mime_type : typing.Optional[re.Match] = re.search(r'([^.]+)$', name)
-        mime_type_str : str = 'jpg'
+        mime_type = re.search(r'([^.]+)$', name)
+        mime_type_str = 'jpg'
         if mime_type:
             mime_type_str = mime_type.group(1).lower()
 
-        file_name : str = re.sub(r'\.([^.]+)$', '', name)
+        file_name = re.sub(r'\.([^.]+)$', '', name)
         file_name = re.sub(r'^file:', '', file_name)
 
-        file_all_name : str = sha224_replace(file_name) + '.' + mime_type_str
-        file_directory : str = os.path.join(load_image_url(), file_all_name)
+        file_all_name = sha224_replace(file_name) + '.' + mime_type_str
+        file_directory = os.path.join(load_image_url(), file_all_name)
 
         if not os.path.exists(file_directory):
             return redirect('/w/' + url_pas(name))

+ 1 - 1
route/give_admin_groups.py

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

+ 1 - 1
route/give_delete_admin_group.py

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

+ 40 - 27
route/give_user_check.py → route/list_user_check.py

@@ -1,20 +1,23 @@
 from .tool.func import *
 
-def give_user_check_2(name):
+def list_user_check(name = 'test', plus_name = None, arg_num = 1, do_type = 'normal'):
+    # 파라미터 to URL
     with get_db_connect() as conn:
         curs = conn.cursor()
 
-        plus_id = flask.request.args.get('plus', None)
+        plus_id = plus_name
+
+        check_type = do_type if do_type in ['simple', 'normal'] else 'normal'
+        check_type = '' if check_type == 'normal' else check_type
+
+        num = arg_num
+        sql_num = (num * 50 - 50) if num * 50 > 0 else 0
 
         if admin_check('all', None, name) == 1 or (plus_id and admin_check('all', None, plus_id) == 1):
             if admin_check() != 1:
                 return re_error('/error/4')
 
-        num = int(number_check(flask.request.args.get('num', '1')))
-        sql_num = (num * 50 - 50) if num * 50 > 0 else 0
-
         div = ''
-        check_type = flask.request.args.get('type', '')
 
         if admin_check(4, (check_type + ' ' if check_type != '' else '') + 'check (' + name + ')') != 1:
             return re_error('/error/3')
@@ -81,14 +84,14 @@ def give_user_check_2(name):
             if record:
                 if not plus_id:
                     div = '' + \
-                        '<a href="/manager/14?plus=' + url_pas(name) + '">(' + load_lang('compare') + ')</a> ' + \
-                        '<a href="/check/' + url_pas(name) + '?type=simple">(' + load_lang('simple_check') + ')</a>' + \
+                        '<a href="/manager/14/' + url_pas(name) + '">(' + load_lang('compare') + ')</a> ' + \
+                        '<a href="/list/user/check/' + url_pas(name) + '/simple">(' + load_lang('simple_check') + ')</a>' + \
                         '<hr class="main_hr">' + \
                     '' + div
                 else:
                     div = '' + \
-                        '<a href="/check/' + url_pas(name) + '">(' + name + ')</a> ' + \
-                        '<a href="/check/' + url_pas(plus_id) + '">(' + plus_id + ')</a>' + \
+                        '<a href="/list/user/check/' + url_pas(name) + '">(' + name + ')</a> ' + \
+                        '<a href="/list/user/check/' + url_pas(plus_id) + '">(' + plus_id + ')</a>' + \
                         '<hr class="main_hr">' + \
                     '' + div
 
@@ -119,16 +122,12 @@ def give_user_check_2(name):
                     div += '''
                         <tr>
                             <td>
-                                <a href="/check/''' + url_pas(data[0]) + '''">''' + data[0] + '''</a>
-                                <a  href="/check_delete''' + \
-                                    '''?name=''' + url_pas(data[0]) + \
-                                    '''&ip=''' + url_pas(data[1]) + \
-                                    '''&time=''' + url_pas(data[3].replace(' ', '').replace(':', '').replace('-', '')) + \
-                                    '''&return_type=''' + ('0' if ip_or_user(name) == 0 else '1') + '''">
+                                <a href="/list/user/check/''' + url_pas(data[0]) + '''">''' + data[0] + '''</a>
+                                <a href="/list/user/check/delete/''' + url_pas(data[0]) + '/' + url_pas(data[1]) + '/' + url_pas(data[3]) + '/' + ('0' if ip_or_user(name) == 0 else '1') + '''">
                                     (''' + load_lang('delete') + ''')
                                 </a>
                             </td>
-                            <td><a href="/check/''' + url_pas(data[1]) + '''">''' + data[1] + '''</a></td>
+                            <td><a href="/list/user/check/''' + url_pas(data[1]) + '''">''' + data[1] + '''</a></td>
                             <td>''' + data[3] + '''</td>
                         </tr>
                         <tr>
@@ -141,37 +140,51 @@ def give_user_check_2(name):
                     </table>
                 '''
 
-            div += next_fix(
-                '/check/' + url_pas(name) + ('?plus=' + plus_id + '&num=' if plus_id else '?num='), 
-                num, 
-                record
-            )
+            if plus_id:
+                div += get_next_page_bottom(
+                    '/list/user/check/' + url_pas(name) + '/normal/{}/' + url_pas(plus_id), 
+                    num, 
+                    record
+                )
+            else:
+                div += next_fix(
+                    '/list/user/check/' + url_pas(name) + '/normal/', 
+                    num, 
+                    record
+                )
+
+            if plus_id:
+                name += ', ' + plus_id
 
             return easy_minify(flask.render_template(skin_check(),
-                imp = [load_lang('check'), wiki_set(), wiki_custom(), wiki_css([0, 0])],
+                imp = [name, wiki_set(), wiki_custom(), wiki_css(['(' + load_lang('check') + ')', 0])],
                 data = div,
                 menu = [['manager', load_lang('return')]]
             ))
         else:
             curs.execute(db_change("" + \
-                "select distinct " + ('name' if ip_or_user(name) == 1 else 'ip') + ", today from ua_d " + \
+                "select distinct " + ('name' if ip_or_user(name) == 1 else 'ip') + " from ua_d " + \
                 "where " + ('ip' if ip_or_user(name) == 1 else 'name') + " = ? "
                 "order by today desc limit ?, 50" + \
             ""), [name, sql_num])
             record = curs.fetchall()
 
             div = ''
-            for i in record:
-                div += '<li><a href="/check/' + url_pas(i[0]) + '?type=simple">' + i[0] + '</a></li>'
+            for for_a in record:
+                div += '<li><a href="/list/user/check/' + url_pas(for_a[0]) + '/simple">' + for_a[0] + '</a></li>'
 
             if div != '':
                 div = '<ul class="opennamu_ul">' + div + '</ul>'
                 div += next_fix(
-                    '/check/' + url_pas(name) + '?type=' + check_type + '&num=', 
+                    '/list/user/check/' + url_pas(name) + '/' + check_type + '/', 
                     num, 
                     record
                 )
 
+            div = '' + \
+                '<a href="/list/user/check/' + url_pas(name) + '/normal">(' + load_lang('check') + ')</a>' + \
+            '' + div
+
             return easy_minify(flask.render_template(skin_check(),
                 imp = [name, wiki_set(), wiki_custom(), wiki_css(['(' + load_lang('simple_check') + ')', 0])],
                 data = div,

+ 5 - 15
route/give_user_check_delete.py → route/list_user_check_delete.py

@@ -1,32 +1,22 @@
 from .tool.func import *
 
-def give_user_check_delete_2():
+def list_user_check_delete(name = None, ip = None, time = None, do_type = 1):
     with get_db_connect() as conn:
         curs = conn.cursor()
 
         if admin_check() != 1:
             return re_error('/error/4')
 
-        user_id = flask.request.args.get('name', None)
-        user_ip = flask.request.args.get('ip', None)
-
-        time = flask.request.args.get('time', None)
-        time_set = re.search(r'([0-9]{4})([0-9]{2})([0-9]{2})([0-9]{2})([0-9]{2})([0-9]{2})', time)
-        if not time_set:
-            return redirect()
-
-        time_set = time_set.groups()
-        time = time_set[0] + '-' + time_set[1] + '-' + time_set[2] + ' '
-        time += time_set[3] + ':' + time_set[4] + ':' + time_set[5]
-
-        return_type = flask.request.args.get('return_type', '1')
+        user_id = name
+        user_ip = ip
+        return_type = do_type
 
         if user_id and user_ip and time:
             if flask.request.method == 'POST':
                 curs.execute(db_change("delete from ua_d where name = ? and ip = ? and today = ?"), [user_id, user_ip, time])
                 conn.commit()
 
-                return redirect('/check/' + url_pas(user_id if return_type == '0' else user_ip))
+                return redirect('/list/user/check/' + url_pas(user_id if return_type == '0' else user_ip))
             else:
                 return easy_minify(flask.render_template(skin_check(),
                     imp = [load_lang('check'), wiki_set(), wiki_custom(), wiki_css(['(' + load_lang('delete') + ')', 0])],

+ 19 - 5
route/login_login.py

@@ -12,10 +12,13 @@ def login_login_2():
             return re_error('/ban')
 
         if flask.request.method == 'POST':
-            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 'login_count' in flask.session:
+                count = int(number_check(flask.session['login_count']))
+                if count > 3:
+                    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)
 
             user_agent = flask.request.headers.get('User-Agent', '')
             user_id = flask.request.form.get('id', '')
@@ -40,6 +43,11 @@ def login_login_2():
                 user_data['encode'],
                 user_id
             ) != 1:
+                if not 'login_count' in flask.session:
+                    flask.session['login_count'] = 1
+                else:
+                    flask.session['login_count'] = int(number_check(flask.session['login_count'])) + 1
+
                 return re_error('/error/10')
 
             curs.execute(db_change('select data from user_set where name = "2fa" and id = ?'), [user_id])
@@ -56,6 +64,12 @@ def login_login_2():
 
                 return redirect('/user')
         else:
+            captcha_data = ''
+            if 'login_count' in flask.session:
+                count = int(number_check(flask.session['login_count']))
+                if count > 3:
+                    captcha_data = captcha_get()
+
             return easy_minify(flask.render_template(skin_check(),
                 imp = [load_lang('login'), wiki_set(), wiki_custom(), wiki_css([0, 0])],
                 data =  '''
@@ -66,7 +80,7 @@ def login_login_2():
                             <hr class="main_hr">
                             <!-- <input type="checkbox" name="auto_login"> ''' + load_lang('auto_login') + ''' (''' + load_lang('not_working') + ''')
                             <hr class="main_hr"> -->
-                            ''' + captcha_get() + '''
+                            ''' + captcha_data + '''
                             <button type="submit">''' + load_lang('login') + '''</button>
                             ''' + http_warning() + '''
                         </form>

+ 5 - 1
route/main_setting_phrase.py

@@ -28,7 +28,8 @@ def main_setting_phrase():
             'topic_text',
             'phrase_user_page_admin',
             'phrase_user_page_owner',
-            'phrase_old_page_warring'
+            'phrase_old_page_warring',
+            'bbs_help'
         ]
         if flask.request.method == 'POST':
             for i in i_list:
@@ -124,6 +125,9 @@ def main_setting_phrase():
 
                         <h2>''' + load_lang('phrase_old_page_warring') + ''' (''' + load_lang('beta') + ''') (HTML)</h2>
                         <textarea class="opennamu_textarea_100" name="''' + i_list[20] + '''">''' + html.escape(d_list[20]) + '''</textarea>
+                        
+                        <h2>''' + load_lang('bbs_help') + '''</h2>
+                        <textarea class="opennamu_textarea_100" name="''' + i_list[13] + '''">''' + html.escape(d_list[22]) + '''</textarea>
 
                         <hr class="main_hr">
                         <button id="opennamu_save_button" type="submit">''' + load_lang('save') + '''</button>

+ 3 - 0
route/main_sys_update.py

@@ -1,3 +1,6 @@
+import zipfile
+import urllib.request
+
 from .tool.func import *
 
 def main_sys_update():

+ 7 - 4
route/main_tool_redirect.py

@@ -4,7 +4,7 @@ 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')],
+            1 : [0, '/list/user/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')],
@@ -15,7 +15,7 @@ def main_tool_redirect(num = 1, add_2 = ''):
             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')],
+            12 : [load_lang('compare_target'), '/list/user/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')],
@@ -30,8 +30,11 @@ def main_tool_redirect(num = 1, add_2 = ''):
             add_1 = flask.request.form.get('name', 'test')
             if flask.request.method == 'POST':
                 if add_2 != '':
-                    flask.session['edit_load_document'] = add_1
-                    return redirect('/edit_from/' + url_pas(add_2))
+                    if num != 12:
+                        flask.session['edit_load_document'] = add_1
+                        return redirect('/edit_from/' + url_pas(add_2))
+                    else:
+                        return redirect(title_list[num][1] + '/' + url_pas(add_2) + '/normal/1/' + url_pas(add_1))
                 elif flask.request.form.get('regex', '') != '':
                     return redirect('/auth/give/ban_regex/' + url_pas(add_1))
                 else:

+ 1 - 1
route/recent_block.py

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

Разница между файлами не показана из-за своего большого размера
+ 464 - 476
route/tool/func.py


+ 14 - 2
route/tool/func_render.py

@@ -61,9 +61,21 @@ class class_do_render:
             ]
 
         if data_type == 'thread' or data_type == 'api_thread':
+            def do_thread_a_change(match):
+                data = match[2].replace('#', '')
+                data_split = data.split('-')
+                if match[1] == 'topic_a' or len(data_split) == 1:
+                    return '<a href="' + match[2] + '">' + match[2] + '</a>'
+                elif match[1] == 'topic_a_post' and len(data_split) == 3:
+                    return '<a href="/bbs/w/' + data_split[2] + '/' + data_split[1] + '#' + data_split[0] + '">#' + data_split[0] + '-' + data_split[1] + '</a>'
+                elif len(data_split) == 2:
+                    return '<a href="/thread/' + data_split[1] + '#' + data_split[0] + '">' + match[2] + '</a>'
+                else:
+                    return ''
+
             data_end[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>',
+                r'&lt;(topic_a(?:_post|_thread)?)&gt;((?:(?!&lt;\/topic_a(?:_post|_thread)?&gt;).)+)&lt;\/topic_a(?:_post|_thread)?&gt;',
+                do_thread_a_change,
                 data_end[0]
             )
             data_end[0] = re.sub(

+ 9 - 8
route/topic.py

@@ -1,6 +1,8 @@
 from .tool.func import *
 
-from .api_topic import api_topic
+from .api_topic import api_topic, api_topic_thread_pre_render
+
+from .edit import edit_editor
 
 def topic(topic_num = 0, do_type = '', doc_name = 'Test'):
     with get_db_connect() as conn:
@@ -12,6 +14,8 @@ def topic(topic_num = 0, do_type = '', doc_name = 'Test'):
         if topic_view_acl == 1:
             return re_error('/ban')
 
+        ip = ip_check()
+
         if flask.request.method == 'POST' and do_type == '':
             if do_edit_slow_check('thread') == 1:
                 return re_error('/error/42')
@@ -38,7 +42,6 @@ def topic(topic_num = 0, do_type = '', doc_name = 'Test'):
             else:
                 captcha_post('', 0)
 
-            ip = ip_check()
             today = get_time()
 
             if topic_acl == 1:
@@ -77,7 +80,7 @@ def topic(topic_num = 0, do_type = '', doc_name = 'Test'):
                 add_alarm(ip_data[0][0], ip, '<a href="/thread/' + topic_num + '#' + num + '">' + html.escape(name) + ' - ' + html.escape(sub) + '#' + num + '</a>')
 
             data = flask.request.form.get('content', 'Test').replace('\r', '')
-            data = get_thread_pre_render(data, num, ip, topic_num, name, sub)
+            data = api_topic_thread_pre_render(curs, data, num, ip, topic_num, name, sub)
 
             do_add_thread(
                 topic_num,
@@ -175,15 +178,13 @@ def topic(topic_num = 0, do_type = '', doc_name = 'Test'):
                             <hr class="main_hr">
                         </div>
                         
-                        <div>''' + edit_button('opennamu_edit_textarea') + '''</div>
-
-                        <textarea id="opennamu_edit_textarea" class="opennamu_textarea_100" placeholder="''' + topic_text + '''" name="content">''' + html.escape(thread_data) + '''</textarea>
+                        ''' + edit_editor(curs, ip, thread_data, 'thread') + '''
                         <hr class="main_hr">
                         
                         ''' + captcha_get() + ip_warning() + '''
                         
-                        <button id="opennamu_save_button" formaction="/thread/''' + topic_num + '''" type="submit">''' + load_lang('send') + '''</button>
-                        <button id="opennamu_preview_button" formaction="/thread_preview/''' + topic_num + '''#opennamu_edit_textarea" type="submit">''' + load_lang('preview') + '''</button>
+                        <button id="opennamu_save_button" formaction="/thread/''' + topic_num + '''" type="submit" onclick="do_monaco_to_textarea(); do_stop_exit_release();">''' + load_lang('send') + '''</button>
+                        <button id="opennamu_preview_button" formaction="/thread_preview/''' + topic_num + '''#opennamu_edit_textarea" type="submit" onclick="do_monaco_to_textarea(); do_stop_exit_release();">''' + load_lang('preview') + '''</button>
                     </form>
                     <hr class="main_hr">
                     

+ 1 - 0
route/topic_list.py

@@ -1,4 +1,5 @@
 from .tool.func import *
+
 from .api_topic import api_topic
 
 def topic_list(name = 'Test'):

+ 1 - 1
route/user_info.py

@@ -49,7 +49,7 @@ def user_info(name = ''):
                 <h2>''' + load_lang('admin') + '''</h2>
                 <ul class="opennamu_ul">
                     <li><a href="/auth/give/ban/''' + url_pas(ip) + '''">''' + ban_name + '''</a></li>
-                    <li><a href="/check/''' + url_pas(ip) + '''">''' + load_lang('check') + '''</a></li>
+                    <li><a href="/list/user/check/''' + url_pas(ip) + '''">''' + load_lang('check') + '''</a></li>
                 </ul>
             '''
         else:

+ 1 - 1
version.json

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

+ 3 - 0
views/main_css/js/func/check_new_thread.ts

@@ -0,0 +1,3 @@
+function opennamu_check_new_thread(do_type : string = '') {
+    
+}

+ 5 - 1
views/main_css/js/func/func.js

@@ -27,7 +27,11 @@ function opennamu_get_main_skin_set(set_name) {
         ) {
             return document.cookie.match(opennamu_cookie_split_regex(set_name))[1];
         } else {
-            return text[set_name][0][0];
+            if(text[set_name]) {
+                return text[set_name][0][0];
+            } else {
+                return '';
+            }
         }
     });
 }

+ 52 - 1
views/main_css/js/route/editor.js

@@ -151,8 +151,57 @@ function do_monaco_to_textarea() {
     }
 }
 
+// https://github.com/microsoft/monaco-editor/issues/568
+class PlaceholderContentWidget {
+    static ID = 'editor.widget.placeholderHint';
+
+    constructor(placeholder, editor) {
+		this.placeholder = placeholder;
+		this.editor = editor;
+        // register a listener for editor code changes
+        editor.onDidChangeModelContent(() => this.onDidChangeModelContent());
+        // ensure that on initial load the placeholder is shown
+        this.onDidChangeModelContent();
+    }
+
+    onDidChangeModelContent() {
+        if (this.editor.getValue() === '') {
+            this.editor.addContentWidget(this);
+        } else {
+            this.editor.removeContentWidget(this);
+        }
+    }
+
+    getId() {
+        return PlaceholderContentWidget.ID;
+    }
+
+    getDomNode() {
+        if (!this.domNode) {
+            this.domNode = document.createElement('div');
+            this.domNode.style.width = 'max-content';
+            this.domNode.textContent = this.placeholder;
+            this.domNode.style.fontStyle = 'italic';
+            this.editor.applyFontInfo(this.domNode);
+        }
+
+        return this.domNode;
+    }
+
+    getPosition() {
+        return {
+            position: { lineNumber: 1, column: 1 },
+            preference: [monaco.editor.ContentWidgetPositionPreference.EXACT],
+        };
+    }
+
+    dispose() {
+        this.editor.removeContentWidget(this);
+    }
+}
+
 function do_monaco_init(monaco_thema) {
-    require.config({ paths: { 'vs': 'https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.37.1/min/vs' }});
+    require.config({ paths: { 'vs': 'https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.40.0/min/vs' }});
     require.config({ 'vs/nls': { availableLanguages: { '*': 'ko' } }});
     require(["vs/editor/editor.main"], function () {
         window.editor = monaco.editor.create(document.getElementById('opennamu_monaco_editor'), {
@@ -162,5 +211,7 @@ function do_monaco_init(monaco_thema) {
             wordWrap: true,
             theme: monaco_thema
         });
+
+        new PlaceholderContentWidget(document.getElementById('opennamu_edit_textarea').placeholder, window.editor);
     });
 }

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


Некоторые файлы не были показаны из-за большого количества измененных файлов