Kaynağa Gözat

Merge pull request #1404 from openNAMU/dev

Dev
잉여개발기 (SPDV) 4 yıl önce
ebeveyn
işleme
7ea6f18c3a
50 değiştirilmiş dosya ile 1678 ekleme ve 2420 silme
  1. 21 37
      app.py
  2. 16 1
      lang/en-US.json
  3. 12 1
      lang/ko-KR.json
  4. 1 1
      readme.md
  5. 102 59
      route/api_user_info.py
  6. 1 1
      route/api_w.py
  7. 6 3
      route/edit.py
  8. 1 0
      route/give_acl.py
  9. 1 1
      route/list_admin_use.py
  10. 1 3
      route/login_logout.py
  11. 1 1
      route/login_register_email.py
  12. 53 61
      route/main_func_setting.py
  13. 1 1
      route/main_func_upload.py
  14. 1 1
      route/recent_history_tool.py
  15. 1 1
      route/search_deep.py
  16. 80 62
      route/tool/func.py
  17. 15 11
      route/tool/func_mark.py
  18. 0 1820
      route/tool/func_new.py
  19. 8 21
      route/tool/func_tool.py
  20. 1 1
      route/topic.py
  21. 2 2
      route/topic_close_list.py
  22. 175 0
      route/user_challenge.py
  23. 1 0
      route/user_info.py
  24. 19 2
      route/user_setting.py
  25. 1 1
      route/user_setting_email.py
  26. 54 49
      route/view_raw.py
  27. 69 54
      route/vote_add.py
  28. 27 24
      route/vote_close.py
  29. 46 44
      route/vote_end.py
  30. 33 32
      route/vote_list.py
  31. 65 52
      route/vote_select.py
  32. 1 1
      version.json
  33. 6 2
      views/main_css/css/main.css
  34. 13 0
      views/main_css/js/func/func.js
  35. 10 0
      views/main_css/js/func/http_warning_text.js
  36. 10 0
      views/main_css/js/func/ie_end_of_life.js
  37. 2 0
      views/main_css/js/func/shortcut.js
  38. 91 0
      views/main_css/js/func/user_name_parser.js
  39. 3 1
      views/main_css/js/load_skin_set.js
  40. 2 12
      views/main_css/js/load_something.js
  41. 0 0
      views/main_css/js/render/html.js
  42. 520 0
      views/main_css/js/render/markdown.js
  43. 15 0
      views/main_css/js/render/onmark.js
  44. 86 0
      views/main_css/js/render/wiki.js
  45. 0 9
      views/main_css/js/render_markdown.js
  46. 37 14
      views/main_css/js/render_onmark.js
  47. 13 9
      views/main_css/js/render_wiki.js
  48. 5 0
      views/main_css/js/route/edit.js
  49. 9 0
      views/main_css/js/route/main_skin_set.js
  50. 40 25
      views/main_css/js/route/thread.js

+ 21 - 37
app.py

@@ -61,6 +61,8 @@ if setup_tool != 'normal':
     create_data = {}
 
     # 폐지 예정 (data_set으로 통합)
+    create_data['data_set'] = ['doc_name', 'doc_rev', 'set_name', 'set_data']
+    
     create_data['data'] = ['title', 'data', 'type']
     create_data['history'] = ['id', 'title', 'data', 'date', 'ip', 'send', 'leng', 'hide', 'type']
     create_data['rc'] = ['id', 'title', 'date', 'type']
@@ -161,7 +163,7 @@ server_set_var = {
         'display' : 'Markup',
         'require' : 'select',
         'default' : 'namumark',
-        'list' : ['namumark', 'custom', 'raw']
+        'list' : ['namumark', 'markdown', 'custom', 'raw']
     }, 'encode' : {
         'display' : 'Encryption method',
         'require' : 'select',
@@ -467,10 +469,10 @@ def view_xref(name = 'Test'):
 def view_xref_this(name = 'Test'):
     return view_xref_2(load_db.db_get(), name, xref_type = '2')
 
-@app.route('/raw/<everything:name>')
-@app.route('/thread/<int:topic_num>/raw/<int:num>')
-def view_raw(name = None, topic_num = None, num = None):
-    return view_raw_2(load_db.db_get(), name, topic_num, num)
+app.route('/raw/<everything:name>')(view_raw_2)
+app.route('/raw/<everything:name>/doc_acl', defaults = { 'doc_acl' : 1 })(view_raw_2)
+app.route('/raw/<everything:name>/doc_rev/<int:num>')(view_raw_2)
+app.route('/thread/<int:topic_num>/raw/<int:num>')(view_raw_2)
 
 @app.route('/diff/<int(signed = True):num_a>/<int(signed = True):num_b>/<everything:name>')
 def view_diff(name = 'Test', num_a = 1, num_b = 1):
@@ -595,6 +597,8 @@ def user_setting_head():
 def user_info(name = ''):
     return user_info_2(load_db.db_get(), name)
 
+app.route('/challenge')(user_challenge)
+
 @app.route('/count')
 @app.route('/count/<name>')
 def user_count_edit(name = None):
@@ -654,42 +658,22 @@ app.route('/login/find')(login_find)
 app.route('/login/find/key', methods = ['POST', 'GET'])(login_find_key)
 app.route('/login/find/email', methods = ['POST', 'GET'], defaults = { 'tool' : 'pass_find' })(login_find_email)
 app.route('/login/find/email/check', methods = ['POST', 'GET'], defaults = { 'tool' : 'check_key' })(login_find_email_check)
-
-@app.route('/logout')
-def login_logout():
-    return login_logout_2(load_db.db_get())
+app.route('/logout')(login_logout)
 
 # Func-vote
-@app.route('/vote/<int:num>', methods = ['POST', 'GET'])
-def vote_select(num = 1):
-    return vote_select_2(load_db.db_get(), str(num))
-
-@app.route('/vote/end/<int:num>')
-def vote_end(num = 1):
-    return vote_end_2(load_db.db_get(), str(num))
-
-@app.route('/vote/close/<int:num>')
-def vote_close(num = 1):
-    return vote_close_2(load_db.db_get(), str(num))
-
-@app.route('/vote')
-@app.route('/vote/list')
-@app.route('/vote/list/<int:num>')
-def vote_list(num = 1):
-    return vote_list_2(load_db.db_get(), 'normal', num)
-
-@app.route('/vote/list/close')
-@app.route('/vote/list/close/<int:num>')
-def vote_list_close(num = 1):
-    return vote_list_2(load_db.db_get(), 'close', num)
-
-@app.route('/vote/add', methods = ['POST', 'GET'])
-def vote_add():
-    return vote_add_2(load_db.db_get())
+app.route('/vote/<int:num>', methods = ['POST', 'GET'])(vote_select)
+app.route('/vote/end/<int:num>')(vote_end)
+app.route('/vote/close/<int:num>')(vote_close)
+app.route('/vote', defaults = { 'list_type' : 'normal' })(vote_list)
+app.route('/vote/list', defaults = { 'list_type' : 'normal' })(vote_list)
+app.route('/vote/list/<int:num>', defaults = { 'list_type' : 'normal' })(vote_list)
+app.route('/vote/list/close', defaults = { 'list_type' : 'close' })(vote_list)
+app.route('/vote/list/close/<int:num>', defaults = { 'list_type' : 'close' })(vote_list)
+app.route('/vote/add', methods = ['POST', 'GET'])(vote_add)
 
 # Func-api
 app.route('/api/w/<everything:name>/doc_tool/<tool>/doc_rev/<int(signed = True):rev>')(api_w)
-app.route('/api/w/<everything:name>/doc_tool/<tool>', methods = ['GET', 'POST'])(api_w)
+app.route('/api/w/<everything:name>/doc_tool/<tool>', methods = ['POST', 'GET'])(api_w)
 app.route('/api/w/<everything:name>', methods = ['GET', 'POST'])(api_w)
 app.route('/api/raw/<everything:name>')(api_raw)
 
@@ -697,7 +681,7 @@ app.route('/api/version', defaults = { 'version_list' : version_list })(api_vers
 app.route('/api/skin_info')(api_skin_info)
 app.route('/api/skin_info/<name>')(api_skin_info)
 app.route('/api/markup')(api_markup)
-app.route('/api/user_info/<name>')(api_user_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>')(api_topic_sub)

+ 16 - 1
lang/en-US.json

@@ -221,6 +221,8 @@
         "key_change" : "Change key",
         "key_delete" : "Delete key",
         "email_delete" : "Delete email",
+        "challenge" : "Challenge",
+        "user_title" : "User title",
         "_comment_2.1_" : "Filter",
             "_comment_2.1.1_" : "List",
                 "interwiki_list" : "Interwiki(s) list",
@@ -409,6 +411,7 @@
         "enter_html" : "Please enter HTML",
         "exp_edit_conflict" : "Editing conflict occurred",
         "same_ip_exist" : "Same IP exists",
+        "old_page_warring" : "This page is out of date.",
         "_comment_3.1_" : "Error",
             "update_error" : "Auto update is not supported.",
             "inter_error" : "Internal error.",
@@ -450,5 +453,17 @@
             "user_head_warning" : "User data will be deleted if you close the browser or when you sign in.",
             "no_login_warning" : "You are not logged in. Your current IP address will be logged within editing or discussing until you log in.",
             "update_warning" : "Manual updates are recommended if your version is 0.2 or lower than the latest version. For Windows, the contents of the route folder will be deleted.",
-            "history_delete_warning" : "If you erase history, it's hard to restore it, so please be careful."
+            "history_delete_warning" : "If you erase history, it's hard to restore it, so please be careful.",
+        "_comment_" : "Challenge",
+            "challenge_title_register" : "Hello, World!",
+            "challenge_info_register" : "Sign up",
+    
+            "challenge_title_first_contribute" : "Well begun is half done.",
+            "challenge_info_first_contribute" : "Make your 1st contribution",
+    
+            "challenge_title_tenthousandth_contribute" : "Rome wasn't built in a day.",
+            "challenge_info_tenthousandth_contribute" : "Make your 1000th contribution",
+    
+            "challenge_title_thousandth_discussion" : "I think, therefore I am.",
+            "challenge_info_thousandth_discussion" : "Post the 1000th discussion thread"
 }

+ 12 - 1
lang/ko-KR.json

@@ -419,5 +419,16 @@
     "topic_text": "토론 기본 문구",
     "hcaptcha": "hCAPTCHA",
     "captcha": "CAPTCHA",
-    "make_new_topic": "새 토론 생성"
+    "make_new_topic": "새 토론 생성",
+    "old_page_warring": "이 문서는 오래되었습니다.",
+    "challenge_title_register": "Hello, World!",
+    "challenge_info_register": "가입을 하세요.",
+    "challenge_title_first_contribute": "시작이 반이다.",
+    "challenge_info_first_contribute": "첫 기여를 하세요.",
+    "challenge_title_tenthousandth_contribute": "대기만성",
+    "challenge_info_tenthousandth_contribute": "1000번째 기여를 하세요.",
+    "challenge_title_thousandth_discussion": "나는 생각한다. 고로 존재한다.",
+    "challenge_info_thousandth_discussion": "1000번째 토론 스레드를 올리세요.",
+    "challenge": "도전과제",
+    "user_title": "칭호"
 }

+ 1 - 1
readme.md

@@ -41,7 +41,7 @@
 
 ## 지원 문법
  * 나무마크 (NamuMark)
- * 마크다운 (Markdown) (예정)
+ * 마크다운 (Markdown) (Beta)
 
 ## 기타
  * 첫 가입자에게 소유자 권한이 부여됩니다.

+ 102 - 59
route/api_user_info.py

@@ -4,73 +4,116 @@ def api_user_info(name = ''):
     with get_db_connect() as conn:
         curs = conn.cursor()
 
-        if flask.request.args.get('render', None):
-            plus_d = ''
-            plus_t = []
+        if flask.request.method == 'POST':
+            try:
+                data_list = json.loads(flask.request.form.get('title_list', ''))
+                data_list = list(set(title_list))
+            except:
+                data_list = [name]
 
-            curs.execute(db_change("update rb set ongoing = '' where end < ? and end != '' and ongoing = '1'"), [get_time()])
-            conn.commit()
+            data_result = {}
+            for user_name in data_list:
+                data_result[user_name] = {}
+                
+                # auth part
+                curs.execute(db_change("select data from user_set where id = ? and name = 'acl'"), [user_name])
+                db_data = curs.fetchall()
+                if db_data:
+                    if db_data[0][0] != 'user':
+                        curs.execute(db_change("select name from alist where name = ?"), [db_data[0][0]])
+                        if curs.fetchall():
+                            data_result[user_name]['auth'] = db_data[0][0]
+                        else:
+                            data_result[user_name]['auth'] = 1
+                    else:
+                        data_result[user_name]['auth'] = 1
+                else:
+                    data_result[user_name]['auth'] = 0
+                
+                # user document part
+                curs.execute(db_change("select title from data where title = ?"), ['user:' + user_name])
+                if curs.fetchall():
+                    data_result[user_name]['document'] = 1
+                else:
+                    data_result[user_name]['document'] = 0
+
+                # user title part
+                curs.execute(db_change('select data from user_set where name = "user_title" and id = ?'), [user_name])
+                db_data = curs.fetchall()
+                if db_data:
+                    data_result[user_name]['user_title'] = db_data[0][0]
+                else:
+                    data_result[user_name]['user_title'] = ''
+                    
+            return flask.jsonify(data_result)
+        else:
+            if flask.request.args.get('render', None):
+                plus_d = ''
+                plus_t = []
 
-            plus_d = '''
-                <table class="user_info_table">
-                    <tbody>
-                        <tr>
-                            <td>''' + load_lang('user_name') + '''</td>
-                            <td>{}</td>
-                        </tr>
-                        <tr>
-                            <td>''' + load_lang('authority') + '''</td>
-                            <td>{}</td>
-                        </tr>
-                        <tr>
-                            <td>''' + load_lang('state') + '''</td>
-                            <td>{}</td>
-                        </tr>
-                    </tbody>
-                </table>
-            '''
+                curs.execute(db_change("update rb set ongoing = '' where end < ? and end != '' and ongoing = '1'"), [get_time()])
+                conn.commit()
 
-            curs.execute(db_change("select data from user_set where id = ? and name = 'acl'"), [name])
-            data = curs.fetchall()
-            if data:
-                if data[0][0] != 'user':
-                    curs.execute(db_change("select name from alist where name = ?"), [data[0][0]])
-                    if curs.fetchall():
-                        plus_t += [data[0][0]]
+                plus_d = '''
+                    <table class="user_info_table">
+                        <tbody>
+                            <tr>
+                                <td>''' + load_lang('user_name') + '''</td>
+                                <td>{}</td>
+                            </tr>
+                            <tr>
+                                <td>''' + load_lang('authority') + '''</td>
+                                <td>{}</td>
+                            </tr>
+                            <tr>
+                                <td>''' + load_lang('state') + '''</td>
+                                <td>{}</td>
+                            </tr>
+                        </tbody>
+                    </table>
+                '''
+
+                curs.execute(db_change("select data from user_set where id = ? and name = 'acl'"), [name])
+                data = curs.fetchall()
+                if data:
+                    if data[0][0] != 'user':
+                        curs.execute(db_change("select name from alist where name = ?"), [data[0][0]])
+                        if curs.fetchall():
+                            plus_t += [data[0][0]]
+                        else:
+                            plus_t += [load_lang('member')]
                     else:
                         plus_t += [load_lang('member')]
                 else:
-                    plus_t += [load_lang('member')]
-            else:
-                plus_t += [load_lang('normal')]
+                    plus_t += [load_lang('normal')]
 
-            if ban_check(name) == 0:
-                plus_t += [load_lang('normal')]
-            else:
-                plus_t += [load_lang('blocked') + '<br>']
-                regex_ban = 0
+                if ban_check(name) == 0:
+                    plus_t += [load_lang('normal')]
+                else:
+                    plus_t += [load_lang('blocked') + '<br>']
+                    regex_ban = 0
 
-                curs.execute(db_change("select login, block, end, why from rb where band = 'regex' and ongoing = '1'"))
-                for test_r in curs.fetchall():
-                    if re.compile(test_r[1]).search(name):
-                        plus_t[1] += load_lang('type') + ' : ' + load_lang('regex')
-                        plus_t[1] += '<br>' + load_lang('period') + ' : ' + (test_r[2] if test_r[2] != '' else load_lang('limitless'))
-                        plus_t[1] += ('<br>' + load_lang('login_able') if test_r[0] == 'O' else '')
-                        plus_t[1] += ('<br>' + load_lang('why') + ' : ' + test_r[3] if test_r[3] != '' else '')
-                        regex_ban = 1
+                    curs.execute(db_change("select login, block, end, why from rb where band = 'regex' and ongoing = '1'"))
+                    for test_r in curs.fetchall():
+                        if re.compile(test_r[1]).search(name):
+                            plus_t[1] += load_lang('type') + ' : ' + load_lang('regex')
+                            plus_t[1] += '<br>' + load_lang('period') + ' : ' + (test_r[2] if test_r[2] != '' else load_lang('limitless'))
+                            plus_t[1] += ('<br>' + load_lang('login_able') if test_r[0] == 'O' else '')
+                            plus_t[1] += ('<br>' + load_lang('why') + ' : ' + test_r[3] if test_r[3] != '' else '')
+                            regex_ban = 1
 
-                if regex_ban == 0:
-                    curs.execute(db_change("select end, login, band, why from rb where block = ? and ongoing = '1'"), [name])
-                    block_data = curs.fetchall()
-                    if block_data:
-                        plus_t[1] += load_lang('type') + ' : ' + (load_lang('band_blocked') if block_data[0][2] == 'O' else load_lang('normal'))
-                        plus_t[1] += (' (' + load_lang('login_able') + ')' if block_data[0][1] != '' else '')
-                        plus_t[1] += '<br>' + load_lang('period') + ' : ' + (block_data[0][0] if block_data[0][0] != '' else load_lang('limitless'))
-                        plus_t[1] += ('<br>' + load_lang('band_blocked') if block_data[0][2] == 'O' else '')
-                        plus_t[1] += ('<br>' + load_lang('why') + ' : ' + block_data[0][3] if block_data[0][3] != '' else '')
+                    if regex_ban == 0:
+                        curs.execute(db_change("select end, login, band, why from rb where block = ? and ongoing = '1'"), [name])
+                        block_data = curs.fetchall()
+                        if block_data:
+                            plus_t[1] += load_lang('type') + ' : ' + (load_lang('band_blocked') if block_data[0][2] == 'O' else load_lang('normal'))
+                            plus_t[1] += (' (' + load_lang('login_able') + ')' if block_data[0][1] != '' else '')
+                            plus_t[1] += '<br>' + load_lang('period') + ' : ' + (block_data[0][0] if block_data[0][0] != '' else load_lang('limitless'))
+                            plus_t[1] += ('<br>' + load_lang('band_blocked') if block_data[0][2] == 'O' else '')
+                            plus_t[1] += ('<br>' + load_lang('why') + ' : ' + block_data[0][3] if block_data[0][3] != '' else '')
 
-            plus_d = plus_d.format(ip_pas(name), plus_t[0], plus_t[1])
+                plus_d = plus_d.format(ip_pas(name), plus_t[0], plus_t[1])
 
-            return flask.jsonify({ "data" : plus_d })
-        else:
-            return flask.jsonify({})
+                return flask.jsonify({ "data" : plus_d })
+            else:
+                return flask.jsonify({})

+ 1 - 1
route/api_w.py

@@ -67,7 +67,7 @@ def api_w(name = 'Test', tool = '', rev = ''):
                     title_list = json.loads(flask.request.form.get('title_list', ''))
                     title_list = list(set(title_list))
                 except:
-                    title_list = []
+                    title_list = [name]
 
                 data_exist = {}
                 for i in title_list:

+ 6 - 3
route/edit.py

@@ -6,7 +6,7 @@ def edit(name = 'Test', name_load = 0, section = 0):
     
         ip = ip_check()
         if acl_check(name) == 1:
-            return re_error('/ban')
+            return redirect('/raw/' + url_pas(name) + '/doc_acl')
         
         curs.execute(db_change("select id from history where title = ? order by id + 0 desc"), [name])
         doc_ver = curs.fetchall()
@@ -137,7 +137,8 @@ def edit(name = 'Test', name_load = 0, section = 0):
             p_text = html.escape(sql_d[0][0]) if sql_d and sql_d[0][0] != '' else load_lang('default_edit_help')
     
             data = re.sub(r'\n+$', '', data)
-    
+            
+            # 이 파트 JS로 이동 예정
             monaco_on = flask.request.cookies.get('main_css_monaco', '0')
             if monaco_on == '1':
                 editor_display = 'style="display: none;"'
@@ -160,7 +161,9 @@ def edit(name = 'Test', name_load = 0, section = 0):
                         window.editor = monaco.editor.create(document.getElementById('monaco_editor'), {
                             value: document.getElementById('textarea_edit_view').value,
                             language: 'plaintext',
-                            theme: \'''' + monaco_thema + '''\'
+                            wordWrap: true,
+                            theme: \'''' + monaco_thema + '''\',
+                            minimap: { enabled: false }
                         });
                     });
                 '''

+ 1 - 0
route/give_acl.py

@@ -111,6 +111,7 @@ def give_acl_2(conn, name):
                 <li>before : ''' + load_lang('before_acl') + '''</li>
                 <li>30_day : ''' + load_lang('30_day_acl') + '''</li>
                 <li>ban_admin : ''' + load_lang('ban_admin_acl') + '''</li>
+                <li>not_all : ''' + load_lang('not_all_acl') + '''</li>
             </ul>
         '''
 

+ 1 - 1
route/list_admin_use.py

@@ -21,7 +21,7 @@ def list_admin_use_2(conn):
 
         get_list = curs.fetchall()
         for data in get_list:
-            list_data += '<li>' + ip_pas(data[0]) + ' / ' + data[1] + ' / ' + data[2] + '</li>'
+            list_data += '<li>' + ip_pas(data[0]) + ' / ' + html.escape(data[1]) + ' / ' + data[2] + '</li>'
 
         list_data += '</ul>'
         list_data += next_fix('/admin_log?num=', num, get_list)

+ 1 - 3
route/login_logout.py

@@ -1,8 +1,6 @@
 from .tool.func import *
 
-def login_logout_2(conn):
-    curs = conn.cursor()
-
+def login_logout():
     flask.session.pop('state', None)
     flask.session.pop('id', None)
 

+ 1 - 1
route/login_register_email.py

@@ -9,7 +9,7 @@ def login_register_email_2(conn):
     if flask.request.method == 'POST':
         flask.session['reg_key'] = load_random_key(32)
 
-        user_email = flask.request.form.get('email', '')
+        user_email = re.sub(r'\\', '', flask.request.form.get('email', ''))
         email_data = re.search(r'@([^@]+)$', user_email)
         if email_data:
             email_data = email_data.group(1)

+ 53 - 61
route/main_func_setting.py

@@ -26,50 +26,33 @@ def main_func_setting(db_set, num = 0):
                 menu = [['manager', load_lang('return')]]
             ))
         elif num == 1:
-            i_list = {
-                0 : 'name',
-                2 : 'frontpage',
-                4 : 'upload',
-                5 : 'skin',
-                7 : 'reg',
-                8 : 'ip_view',
-                9 : 'back_up',
-                10 : 'port',
-                11 : 'key',
-                12 : 'update',
-                15 : 'encode',
-                16 : 'host',
-                19 : 'slow_edit',
-                20 : 'requires_approval',
-                21 : 'backup_where',
-                22 : 'domain',
-                23 : 'ua_get'
-            }
-            n_list = {
-                0 : 'Wiki',
-                2 : 'FrontPage',
-                4 : '2',
-                5 : '',
-                7 : '',
-                8 : '',
-                9 : '0',
-                10 : '3000',
-                11 : 'test',
-                12 : 'stable',
-                15 : 'sha3',
-                16 : '0.0.0.0',
-                19 : '0',
-                20 : '',
-                21 : '',
-                22 : flask.request.host_url,
-                23 : ''
+            setting_list = {
+                0 : ['name', 'Wiki'],
+                2 : ['frontpage', 'FrontPage'],
+                4 : ['upload', '2'],
+                5 : ['skin', ''],
+                7 : ['reg', ''],
+                8 : ['ip_view', ''],
+                9 : ['back_up', '0'],
+                10 : ['port', '3000'],
+                11 : ['key', load_random_key()],
+                12 : ['update', 'stable'],
+                15 : ['encode', 'sha3'],
+                16 : ['host', '0.0.0.0'],
+                19 : ['slow_edit', '0'],
+                20 : ['requires_approval', ''],
+                21 : ['backup_where', ''],
+                22 : ['domain', flask.request.host_url],
+                23 : ['ua_get', ''],
+                24 : ['enable_comment', ''],
+                25 : ['enable_challenge', '']
             }
 
             if flask.request.method == 'POST':
-                for i in i_list:
+                for i in setting_list:
                     curs.execute(db_change("update other set data = ? where name = ?"), [
-                        flask.request.form.get(i_list[i], n_list[i]),
-                        i_list[i]
+                        flask.request.form.get(setting_list[i][0], setting_list[i][1]),
+                        setting_list[i][0]
                     ])
 
                 conn.commit()
@@ -79,18 +62,15 @@ def main_func_setting(db_set, num = 0):
                 return redirect('/setting/1')
             else:
                 d_list = {}
+                for i in setting_list:
+                    curs.execute(db_change('select data from other where name = ?'), [setting_list[i][0]])
+                    db_data = curs.fetchall()
+                    if not db_data:
+                        curs.execute(db_change('insert into other (name, data) values (?, ?)'), [setting_list[i][0], setting_list[i][1]])
 
-                for i in i_list:
-                    curs.execute(db_change('select data from other where name = ?'), [i_list[i]])
-                    sql_d = curs.fetchall()
-                    if sql_d:
-                        d_list[i] = sql_d[0][0]
-                    else:
-                        curs.execute(db_change('insert into other (name, data) values (?, ?)'), [i_list[i], n_list[i]])
-
-                        d_list[i] = n_list[i]
-
-                conn.commit()
+                    d_list[i] = db_data[0][0] if db_data else setting_list[i][1]
+                else:
+                    conn.commit()
 
                 acl_div = ['']
                 encode_data = ['sha256', 'sha3']
@@ -100,7 +80,7 @@ def main_func_setting(db_set, num = 0):
                     else:
                         acl_div[0] += '<option value="' + acl_data + '">' + acl_data + '</option>'
 
-                check_box_div = ['', '', '', '', '']
+                check_box_div = ['', '', '', '', '', '', '']
                 for i in range(0, len(check_box_div)):
                     if i == 0:
                         acl_num = 7
@@ -108,8 +88,12 @@ def main_func_setting(db_set, num = 0):
                         acl_num = 8
                     elif i == 3:
                         acl_num = 20
-                    else:
+                    elif i == 4:
                         acl_num = 23
+                    elif i == 5:
+                        acl_num = 24
+                    elif i == 6:
+                        acl_num = 25
 
                     if d_list[acl_num]:
                         check_box_div[i] = 'checked="checked"'
@@ -144,7 +128,7 @@ def main_func_setting(db_set, num = 0):
 
                             <span>''' + load_lang('domain') + '''</span> (EX : http://2du.pythonanywhere.com/)
                             <hr class="main_hr">
-                            <input name="''' + i_list[22] + '''" value="''' + html.escape(d_list[22]) + '''">
+                            <input name="''' + setting_list[22][0] + '''" value="''' + html.escape(d_list[22]) + '''">
                             <hr class="main_hr">
 
                             <span>''' + load_lang('wiki_host') + '''</span>
@@ -165,6 +149,13 @@ def main_func_setting(db_set, num = 0):
                             <span>''' + load_lang('encryption_method') + '''</span>
                             <hr class="main_hr">
                             <select name="encode">''' + acl_div[0] + '''</select>
+                            
+                            <h3>1.1. ''' + load_lang('communication_function') + '''</h3>
+                            <input type="checkbox" name="enable_comment" ''' + check_box_div[5] + '''> ''' + load_lang('enable_comment_function') + '''
+                            <hr class="main_hr">
+                            
+                            <input type="checkbox" name="enable_challenge" ''' + check_box_div[6] + '''> ''' + load_lang('enable_challenge_function') + '''
+                            <hr class="main_hr">
 
                             <h2>2. ''' + load_lang('design_set') + '''</h2>
                             <span>''' + load_lang('wiki_skin') + '''</span>
@@ -188,8 +179,13 @@ def main_func_setting(db_set, num = 0):
                             <hr class="main_hr">
                             <input name="upload" value="''' + html.escape(d_list[4]) + '''">
                             <hr class="main_hr">
-
+                            
+                            <span>''' + load_lang('update_branch') + '''</span>
+                            <hr class="main_hr">
+                            <select name="update">''' + branch_div + '''</select>
+                            
                             <span ''' + sqlite_only + '''>
+                                <h3>4.1. ''' + load_lang('sqlite') + '''</h3>
                                 <span>
                                     ''' + load_lang('backup_interval') + ' (' + load_lang('hour') + ') (' + load_lang('off') + ' : 0) ' + \
                                     '(' + load_lang('restart_required') + ''')</span>
@@ -199,24 +195,20 @@ def main_func_setting(db_set, num = 0):
 
                                 <span>
                                     ''' + load_lang('backup_where') + ' (' + load_lang('empty') + ' : ' + load_lang('default') + ') ' + \
-                                    '(' + load_lang('restart_required') + ''') (EX : ./data/backup.db)
+                                    '(' + load_lang('restart_required') + ''') (''' + load_lang('example') + ''' : ./data/backup.db)
                                 </span>
                                 <hr class="main_hr">
                                 <input name="backup_where" value="''' + html.escape(d_list[21]) + '''">
                                 <hr class="main_hr">
                             </span>
 
-                            <span>''' + load_lang('update_branch') + '''</span>
-                            <hr class="main_hr">
-                            <select name="update">''' + branch_div + '''</select>
-
                             <h2>5. ''' + load_lang('edit_set') + '''</h2>
                             <span><a href="/setting/8">(''' + load_lang('main_acl_setting') + ''')</a></span>
                             <hr class="main_hr">
 
                             <span>''' + load_lang('slow_edit') + ' (' + load_lang('second') + ') (' + load_lang('off') + ''' : 0)</span>
                             <hr class="main_hr">
-                            <input name="''' + i_list[19] + '''" value="''' + html.escape(d_list[19]) + '''">
+                            <input name="''' + setting_list[19][0] + '''" value="''' + html.escape(d_list[19]) + '''">
 
                             <hr class="main_hr">
                             <button id="save" type="submit">''' + load_lang('save') + '''</button>

+ 1 - 1
route/main_func_upload.py

@@ -113,7 +113,7 @@ def main_func_upload():
             return redirect('/w/file:' + name)
         else:
             license_list = '<option value="direct_input">' + load_lang('direct_input') + '</option>'
-            file_name = flask.request.args.get('name', '')
+            file_name = html.escape(flask.request.args.get('name', ''))
 
             curs.execute(db_change("select html from html_filter where kind = 'image_license'"))
             db_data = curs.fetchall()

+ 1 - 1
route/recent_history_tool.py

@@ -8,7 +8,7 @@ def recent_history_tool_2(conn, name, rev):
     data = '' + \
         '<h2>' + load_lang('tool') + '</h2>' + \
         '<ul class="inside_ul">' + \
-            '<li><a href="/raw/' + url_pas(name) + '?num=' + num + '">' + load_lang('raw') + '</a></li>' + \
+            '<li><a href="/raw/' + url_pas(name) + '/doc_rev/' + num + '">' + load_lang('raw') + '</a></li>' + \
     ''
 
     data += '<li><a href="/revert/' + url_pas(name) + '?num=' + num + '">' + load_lang('revert') + ' | r' + num + '</a></li>'

+ 1 - 1
route/search_deep.py

@@ -46,7 +46,7 @@ def search_deep_2(conn, name):
 
                     test = data[1]
 
-                div_plus += '<li><a href="/w/' + url_pas(data[0]) + '">' + data[0] + '</a> (' + data[1] + ')</li>'
+                div_plus += '<li><a href="/w/' + url_pas(data[0]) + '">' + html.escape(data[0]) + '</a> (' + data[1] + ')</li>'
     else:
         curs.execute(db_change("select title from data where title like ? order by title limit ?, 50"),
             ['%' + name + '%', sql_num]

+ 80 - 62
route/tool/func.py

@@ -35,10 +35,16 @@ if data_up_date == 1:
         f.write(version_list['beta']['r_ver'])
     
     if platform.system() in ('Linux', 'Windows'):
-        os.system(
-            'python' + ('3' if platform.system() != 'Windows' else '') + ' ' + \
-            '-m pip install --upgrade --user -r requirements.txt'
-        )
+        if platform.python_implementation() == 'PyPy':
+            os.system(
+                'pypy' + ('3' if platform.system() != 'Windows' else '') + ' ' + \
+                '-m pip install --upgrade --user -r requirements.txt'
+            )
+        else:
+            os.system(
+                'python' + ('3' if platform.system() != 'Windows' else '') + ' ' + \
+                '-m pip install --upgrade --user -r requirements.txt'
+            )
         
         print('----')
         try:
@@ -85,9 +91,6 @@ global_wiki_set = {}
 
 global_db_set = ''
 
-data_css_ver = '123'
-data_css = ''
-
 conn = ''
 
 # Func
@@ -534,6 +537,8 @@ def update(ver_num, set_data):
             ), ['application', i[0], json.dumps(sql_data)])
     
     conn.commit()
+    
+    # 아이피 상태인 이메일 제거 예정
 
     print('Update completed')
 
@@ -599,6 +604,19 @@ def set_init():
 def get_default_admin_group():
     return ['owner', 'ban']
 
+def get_user_title_list():
+    # default
+    user_title = {
+        '' : load_lang('default'),
+        '🌳' : '🌳 namu',
+    }
+    
+    # admin
+    if admin_check('all') == 1:
+        user_title['✅'] = '✅ admin'
+    
+    return user_title
+
 def load_random_key(long = 128):
     return ''.join(
         random.choice(
@@ -608,15 +626,9 @@ def load_random_key(long = 128):
 
 def http_warning():
     return '''
-        <div id="http_warning_text"></div>
-        <script>
-            if(window.location.protocol !== 'https:') {
-                document.getElementById('http_warning_text').innerHTML = "''' + \
-                    load_lang('http_warning') + \
-                '''";
-                document.getElementById('http_warning_text').style.margin = "10px 0px 0px 0px";
-            }
-        </script>
+        <div id="opennamu_http_warning_text"></div>
+        <span style="display: none;" id="opennamu_http_warning_text_lang">''' + load_lang('http_warning') + '''</span>
+        <script>opennamu_do_warning_text();</script>
     '''
 
 def next_fix(link, num, page, end = 50):
@@ -667,7 +679,7 @@ def get_acl_list(type_d = 'normal'):
     if type_d == 'user':
         return ['', 'user', 'all']
     else:
-        return ['', 'all', 'user', 'admin', 'owner', '50_edit', 'email', 'ban', 'before', '30_day', 'ban_admin']
+        return ['', 'all', 'user', 'admin', 'owner', '50_edit', 'email', 'ban', 'before', '30_day', 'ban_admin', 'not_all']
 
 ## Func-simple-with_DB
 def load_image_url():
@@ -862,48 +874,57 @@ def skin_check(set_n = 0):
     
 def wiki_css(data):
     # without_DB
-
-    global data_css
-    global data_css_ver
-
     data += ['' for _ in range(0, 3 - len(data))]
+    
+    data_css = ''
+    data_css_ver = '145'
+    
+    # Func JS
+    data_css += '<script src="/views/main_css/js/func/func.js?ver=' + data_css_ver + '"></script>'
+    
+    data_css += '<script src="/views/main_css/js/func/http_warning_text.js?ver=' + data_css_ver + '"></script>'
+    data_css += '<script src="/views/main_css/js/func/ie_end_of_life.js?ver=' + data_css_ver + '"></script>'
+    data_css += '<script src="/views/main_css/js/func/shortcut.js?ver=' + data_css_ver + '"></script>'
+    data_css += '<script src="/views/main_css/js/func/user_name_parser.js?ver=' + data_css_ver + '"></script>'
+    
+    # Render JS
+    data_css += '<script src="/views/main_css/js/render/markdown.js?ver=' + data_css_ver + '"></script>'
+    data_css += '<script src="/views/main_css/js/render/wiki.js?ver=' + data_css_ver + '"></script>'
+    
+    # Route JS
+    data_css += '<script src="/views/main_css/js/route/thread.js?ver=' + data_css_ver + '"></script>'
+    
+    # 레거시 일반 JS
+    data_css += '<script src="/views/main_css/js/load_editor.js?ver=' + data_css_ver + '"></script>'
+    data_css += '<script src="/views/main_css/js/load_skin_set.js?ver=' + data_css_ver + '"></script>'
+    data_css += '<script src="/views/main_css/js/load_something.js?ver=' + data_css_ver + '"></script>'
+    
+    # 레거시 렌더러 JS
+    data_css += '<script src="/views/main_css/js/render_html.js?ver=' + data_css_ver + '"></script>'
+    data_css += '<script src="/views/main_css/js/render_onmark.js?ver=' + data_css_ver + '"></script>'
+    data_css += '<script src="/views/main_css/js/render_wiki.js?ver=' + data_css_ver + '"></script>'
+    
+    # Main CSS
+    data_css += '<link rel="stylesheet" href="/views/main_css/css/main.css?ver=' + data_css_ver + '">'
+    
+    # External
+    data_css += '<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.5.0/build/styles/default.min.css">'
+    data_css += '<script src="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.5.0/build/highlight.min.js"></script>'
+    
+    data_css += '<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.15.3/dist/katex.min.css" integrity="sha384-KiWOvVjnN8qwAZbuQyWDIbfCLFhLXNETzBQjA/92pIowpC0d2O3nppDGQVgwd2nB" crossorigin="anonymous">'
+    data_css += '<script defer src="https://cdn.jsdelivr.net/npm/katex@0.15.3/dist/katex.min.js" integrity="sha384-0fdwu/T/EQMsQlrHCCHoH10pkPLlKA1jL5dFyUOvB3lfeT2540/2g6YgSi2BL14p" crossorigin="anonymous"></script>'
 
-    if data_css == '':
-        for i_data in os.listdir(os.path.join("views", "main_css", "css")):
-            if i_data != 'sub':
-                data_css += '<link rel="stylesheet" href="/views/main_css/css/' + i_data + '?ver=' + data_css_ver + '">'
-
-        for i_data in os.listdir(os.path.join("views", "main_css", "js")):
-            if i_data != 'sub':
-                data_css += '<script src="/views/main_css/js/' + i_data + '?ver=' + data_css_ver + '"></script>'
-                
-    data = data[0:2] + ['', '''
-        <link   rel="stylesheet"
-                href="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.2.0/build/styles/default.min.css">
-        <script src="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.2.0/build/highlight.min.js"></script>
-        <link   defer rel="stylesheet"
-                href="https://cdn.jsdelivr.net/npm/katex@0.13.2/dist/katex.min.css"
-                integrity="sha384-Cqd8ihRLum0CCg8rz0hYKPoLZ3uw+gES2rXQXycqnL5pgVQIflxAUDS7ZSjITLb5"
-                crossorigin="anonymous">
-        <script src="https://cdn.jsdelivr.net/npm/katex@0.13.2/dist/katex.min.js"
-                integrity="sha384-1Or6BdeNQb0ezrmtGeqQHFpppNd7a/gw29xeiSikBbsb44xu3uAo8c7FwbF5jhbd"
-                crossorigin="anonymous"></script>
-    ''' + data_css + '<script>window.addEventListener(\'DOMContentLoaded\', main_css_skin_load);</script>'] + data[2:]
+    data = data[0:2] + ['', data_css] + data[2:]
 
     return data
 
 def cut_100(data):
     # without_DB
-
-    data = re.search(r'<pre style="display: none;" id="render_content_load">([^<>]+)<\/pre>', data)
-    if data:
-        data = data.group(1)
-        if len(data) > 100:
-            return data[0:100] + '...'
-        else:
-            return data[0:len(data)]
-    else:
-        return ''
+    
+    data = data.replace('<pre class="render_content_load" id="render_content_load">', '')
+    data = data.replace('</pre>', ' ' * 100)
+    
+    return data[0 : 100]
 
 def wiki_set(num = 1):
     curs = conn.cursor()
@@ -1421,7 +1442,7 @@ def acl_check(name = 'test', tool = '', topic_num = '1'):
         if acl_data[0][0] != 'normal':
             if not acl_data[0][0] in ['ban', 'ban_admin'] and get_ban == 1 and tool != 'render':
                 return 1
-
+            
             if acl_data[0][0] in ['all', 'ban']:
                 return 0
             elif acl_data[0][0] == 'user':
@@ -1490,6 +1511,8 @@ def acl_check(name = 'test', tool = '', topic_num = '1'):
             elif acl_data[0][0] == 'ban_admin':
                 if admin_check(1) == 1 or get_ban == 1:
                     return 0
+            elif acl_data[0][0] == 'not_all':
+                return 1
 
             return 1
         elif i == (end - 1):
@@ -1556,12 +1579,11 @@ def ban_check(ip = None, tool = ''):
 
     return 0
 
-def ip_pas(raw_ip, type_d = 0):
+def ip_pas(raw_ip, type_data = 0):
     curs = conn.cursor()
 
     hide = 0
     end_ip = {}
-    i = 0
 
     return_data = 0
     if type(raw_ip) != type([]):
@@ -1578,7 +1600,7 @@ def ip_pas(raw_ip, type_d = 0):
     
     get_ip = list(set(get_ip))
     
-    for raw_ip in 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 != '':
@@ -1589,12 +1611,8 @@ def ip_pas(raw_ip, type_d = 0):
         else:     
             ip = raw_ip
             
-        if type_d == 0:
-            if is_this_ip == 0:
-                ip = '<a href="/w/' + url_pas('user:' + raw_ip) + '">' + raw_ip + '</a>'
-                
-            if change_ip == 0:
-                ip += ' <a href="/user/' + url_pas(raw_ip) + '">(' + load_lang('tool') + ')</a>'
+        if type_data == 0 and change_ip == 0:
+            ip = '<span class="opennamu_ip_render">' + raw_ip + '</span>'
 
         end_ip[raw_ip] = ip
     

+ 15 - 11
route/tool/func_mark.py

@@ -113,32 +113,36 @@ class class_do_render:
         if data_type != 'backlink':
             if rep_data == 'namumark':
                 data_in = (data_in + '_') if data_in else ''
+                doc_data = html.escape(doc_data)
+                doc_name = html.escape(doc_name)
+                
                 data_end = [
-                    '<pre style="display: none;" id="' + data_in + 'render_content_load">' + html.escape(doc_data) + '</pre>' + \
+                    '<pre class="render_content_load" id="' + data_in + 'render_content_load">' + doc_data + '</pre>' + \
                     '<div class="render_content" id="' + data_in + 'render_content"></div>', 
                     '''
                         do_onmark_render(
                             test_mode = "normal", 
                             name_id = "''' + data_in + '''render_content",
                             name_include = "''' + data_in + '''",
-                            name_doc = "''' + doc_name.replace('"', '\\"') + '''"
+                            name_doc = "''' + doc_name + '''"
                         );
                     ''',
                     []
                 ]
             elif rep_data == 'markdown':
                 data_in = (data_in + '_') if data_in else ''
+                doc_data = html.escape(doc_data)
+                doc_name = html.escape(doc_name)
+                
                 data_end = [
-                    '<pre style="display: none;" id="' + data_in + 'render_content_load">' + html.escape(doc_data) + '</pre>' + \
+                    '<pre class="render_content_load" id="' + data_in + 'render_content_load">' + html.escape(doc_data) + '</pre>' + \
                     '<div class="render_content" id="' + data_in + 'render_content"></div>', 
-                    '''
-                        do_onmark_render(
-                            test_mode = "normal", 
-                            name_id = "''' + data_in + '''render_content",
-                            name_include = "''' + data_in + '''",
-                            name_doc = "''' + doc_name.replace('"', '\\"') + '''"
-                        );
-                    ''',
+                    'new opennamu_render_markdown(' + \
+                        'render_part_id = "render_content_load",' + \
+                        'render_part_id_after = "render_content",' + \
+                        'render_part_id_add = "' + data_in + '",' + \
+                        'doc_name = "' + doc_name + '"' + \
+                    ').do_main();',
                     []
                 ]
             else:

+ 0 - 1820
route/tool/func_new.py

@@ -1,1820 +0,0 @@
-# Init
-import os
-import sys
-import platform
-import json
-import smtplib
-import zipfile
-import shutil
-import logging
-import random
-
-import email.mime.text
-import email.utils
-import email.header
-
-import urllib.request
-
-# Init-Version
-version_list = json.loads(open('version.json', encoding = 'utf8').read())
-
-print('Version : ' + version_list['beta']['r_ver'])
-print('DB set version : ' + version_list['beta']['c_ver'])
-print('Skin set version : ' + version_list['beta']['s_ver'])
-print('----')
-
-# Init-PIP_Install
-data_up_date = 1
-if os.path.exists(os.path.join('data', 'version.json')):
-    data_load_ver = open(os.path.join('data', 'version.json'), encoding = 'utf8').read()
-    if data_load_ver == version_list['beta']['r_ver']:
-        data_up_date = 0
-
-if data_up_date == 1:
-    with open(os.path.join('data', 'version.json'), 'w', encoding = 'utf8') as f:
-        f.write(version_list['beta']['r_ver'])
-    
-    if platform.system() in ('Linux', 'Windows'):
-        os.system(
-            'python' + ('3' if platform.system() != 'Windows' else '') + ' ' + \
-            '-m pip install --upgrade --user -r requirements.txt'
-        )
-        
-        print('----')
-        try:
-            os.execl(sys.executable, sys.executable, *sys.argv)
-        except:
-            pass
-
-        try:
-            os.execl(sys.executable, '"' + sys.executable + '"', *sys.argv)
-        except:
-            print('Error : restart failed')
-            raise
-    else:
-        print('Error : automatic installation is not supported.')
-        print('Help : try "python3 -m pip install -r requirements.txt"')
-else:
-    print('PIP check pass')
-    
-print('----')
-
-# Init-Load
-from .func_mark import *
-
-from diff_match_patch import diff_match_patch
-
-import netius.servers
-
-import werkzeug.routing
-import werkzeug.debug
-
-import flask
-
-import requests
-
-import pymysql
-
-if sys.version_info < (3, 6):
-    import sha3
-   
-# Init-Global
-global_lang = {}
-global_wiki_set = {}
-
-global_db_set = ''
-
-data_css_ver = '118'
-data_css = ''
-
-conn = ''
-
-# Func
-# Func-main
-def load_conn(data):
-    global conn
-
-    conn = data
-    
-def do_db_set(db_set):
-    global global_db_set
-    
-    global_db_set = db_set
-    
-# Func-init
-class get_db_connect_old:
-    def __init__(self, db_set):
-        self.db_set = db_set
-        self.conn = ''
-        
-    def db_load(self):
-        if self.db_set['type'] == 'sqlite':
-            self.conn = sqlite3.connect(self.db_set['name'] + '.db')
-        else:
-            self.conn = pymysql.connect(
-                host = self.db_set['mysql_host'],
-                user = self.db_set['mysql_user'],
-                password = self.db_set['mysql_pw'],
-                charset = 'utf8mb4',
-                port = int(self.db_set['mysql_port']),
-            )
-            curs = self.conn.cursor()
-
-            try:
-                curs.execute(db_change(
-                    'create database ' + self.db_set['name'] + ' ' + \
-                    'default character set utf8mb4;'
-                ))
-            except:
-                pass
-
-            self.conn.select_db(self.db_set['name'])
-
-        load_conn(self.conn)
-
-        return self.conn
-    
-    def db_get(self):
-        # if self.db_set['type'] != 'sqlite':
-        #     self.conn.ping(reconnect = True)
-            
-        return self.conn
-    
-class get_db_connect:
-    def __init__(self):
-        global global_db_set
-        
-        self.db_set = global_db_set
-        
-    def __enter__(self):
-        if self.db_set['type'] == 'sqlite':
-            self.conn = sqlite3.connect(self.db_set['name'] + '.db')
-        else:
-            self.conn = pymysql.connect(
-                host = self.db_set['mysql_host'],
-                user = self.db_set['mysql_user'],
-                password = self.db_set['mysql_pw'],
-                charset = 'utf8mb4',
-                port = int(self.db_set['mysql_port']),
-            )
-            curs = self.conn.cursor()
-
-            try:
-                curs.execute(db_change(
-                    'create database ' + self.db_set['name'] + ' ' + \
-                    'default character set utf8mb4;'
-                ))
-            except:
-                pass
-
-            self.conn.select_db(self.db_set['name'])
-
-        return self.conn
-    
-    def __exit__(self, exc_type, exc_value, traceback):
-        self.conn.close()
-
-def update(ver_num, set_data):
-    curs = conn.cursor()
-
-    print('----')
-    # 업데이트 하위 호환 유지 함수
-
-    if ver_num < 3160027:
-        print('Add init set')
-        set_init()
-
-    if ver_num < 3170002:
-        curs.execute(db_change("select html from html_filter where kind = 'extension'"))
-        if not curs.fetchall():
-            for i in ['jpg', 'jpeg', 'png', 'gif', 'webp']:
-                curs.execute(db_change(
-                    "insert into html_filter (html, kind) values (?, 'extension')"
-                ), [i])
-
-    if ver_num < 3170400:
-        curs.execute(db_change("select title, sub, code from topic where id = '1'"))
-        for i in curs.fetchall():
-            curs.execute(db_change(
-                "update topic set code = ? where title = ? and sub = ?"
-            ), [
-                i[2], 
-                i[0], 
-                i[1]
-            ])
-            curs.execute(db_change(
-                "update rd set code = ? where title = ? and sub = ?"
-            ), [
-                i[2], 
-                i[0], 
-                i[1]
-            ])
-
-    if ver_num < 3171800:
-        curs.execute(db_change("select data from other where name = 'recaptcha'"))
-        change_rec = curs.fetchall()
-        if change_rec and change_rec[0][0] != '':
-            new_rec = re.search(r'data-sitekey="([^"]+)"', change_rec[0][0])
-            if new_rec:
-                curs.execute(db_change(
-                    "update other set data = ? where name = 'recaptcha'"
-                ), [new_rec.group(1)])
-            else:
-                curs.execute(db_change("update other set data = '' where name = 'recaptcha'"))
-                curs.execute(db_change("update other set data = '' where name = 'sec_re'"))
-    
-    if  ver_num < 3172800 and \
-        set_data['db_type'] == 'mysql':
-        get_data_mysql = json.loads(open('data/mysql.json', encoding = 'utf8').read())
-        
-        with open('data/mysql.json', 'w') as f:
-            f.write('{ "user" : "' + get_data_mysql['user'] + '", "password" : "' + get_data_mysql['password'] + '", "host" : "localhost" }')
-
-    if ver_num < 3183603:
-        curs.execute(db_change("select block from ban where band = 'O'"))
-        for i in curs.fetchall():
-            curs.execute(db_change(
-                "update ban set block = ?, band = 'regex' where block = ? and band = 'O'"
-            ), [
-                '^' + i[0].replace('.', '\\.'),
-                i[0]
-            ])
-
-        curs.execute(db_change("select block from rb where band = 'O'"))
-        for i in curs.fetchall():
-            curs.execute(db_change(
-                "update rb set block = ?, band = 'regex' where block = ? and band = 'O'"
-            ), [
-                '^' + i[0].replace('.', '\\.'),
-                i[0]
-            ])
-
-    if ver_num < 3190201:
-        today_time = get_time()
-
-        curs.execute(db_change("select block, end, why, band, login from ban"))
-        for i in curs.fetchall():
-            curs.execute(db_change(
-                "insert into rb (block, end, today, why, band, login, ongoing) " + \
-                "values (?, ?, ?, ?, ?, ?, ?)"
-            ), [
-                i[0],
-                i[1],
-                today_time,
-                i[2],
-                i[3],
-                i[4],
-                '1'
-            ])
-
-    if ver_num < 3191301:
-        curs.execute(db_change('' + \
-            'select id, title, date from history ' + \
-            'where not title like "user:%" ' + \
-            'order by date desc ' + \
-            'limit 50' + \
-        ''))
-        data_list = curs.fetchall()
-        for get_data in data_list:
-            curs.execute(db_change(
-                "insert into rc (id, title, date, type) values (?, ?, ?, 'normal')"
-            ), [
-                get_data[0], 
-                get_data[1],
-                get_data[2]
-            ])
-
-    if ver_num < 3202400:
-        curs.execute(db_change("select data from other where name = 'update'"))
-        get_data = curs.fetchall()
-        if get_data and get_data[0][0] == 'master':
-            curs.execute(db_change("update other set data = 'beta' where name = 'update'"), [])
-
-    if ver_num < 3202600:
-        curs.execute(db_change("select name, regex, sub from filter"))
-        for i in curs.fetchall():
-            curs.execute(db_change(
-                "insert into html_filter (html, kind, plus, plus_t) " + \
-                "values (?, 'regex_filter', ?, ?)"
-            ), [
-                i[0], 
-                i[1],
-                i[2]
-            ])
-
-        curs.execute(db_change("select title, link, icon from inter"))
-        for i in curs.fetchall():
-            curs.execute(db_change(
-                "insert into html_filter (html, kind, plus, plus_t) " + \
-                "values (?, 'inter_wiki', ?, ?)"), [
-                i[0], 
-                i[1],
-                i[2]
-            ])
-
-    if ver_num < 3203400:
-        curs.execute(db_change("select user, css from custom"))
-        for i in curs.fetchall():
-            curs.execute(db_change(
-                "insert into user_set (name, id, data) values ('custom_css', ?, ?)"
-            ), [
-                re.sub(r' \(head\)$', '', i[0]), 
-                i[1]
-            ])
-
-    if ver_num < 3205500:
-        curs.execute(db_change("select title, decu, dis, view, why from acl"))
-        for i in curs.fetchall():
-            curs.execute(db_change(
-                "insert into acl (title, data, type) values (?, ?, ?)"
-            ), [i[0], i[1], 'decu'])
-            curs.execute(db_change(
-                "insert into acl (title, data, type) values (?, ?, ?)"
-            ), [i[0], i[2], 'dis'])
-            curs.execute(db_change(
-                "insert into acl (title, data, type) values (?, ?, ?)"
-            ), [i[0], i[3], 'view'])
-            curs.execute(db_change(
-                "insert into acl (title, data, type) values (?, ?, ?)"
-            ), [i[0], i[4], 'why'])
-
-    if ver_num < 3300101:
-        # 캐시 초기화
-        curs.execute(db_change('delete from cache_data'))
-    
-    if ver_num < 3300301:
-        # regex_filter 오류 해결
-        curs.execute(db_change(
-            'delete from html_filter where kind = "regex_filter" and html is null'
-        ))
-        
-    if ver_num < 3302302:
-        # user이랑 user_set 테이블의 통합
-        curs.execute(db_change('select id, pw, acl, date, encode from user'))
-        for i in curs.fetchall():
-            curs.execute(db_change(
-                "insert into user_set (name, id, data) values (?, ?, ?)"
-            ), ['pw', i[0], i[1]])
-            curs.execute(db_change(
-                "insert into user_set (name, id, data) values (?, ?, ?)"
-            ), ['acl', i[0], i[2]])
-            curs.execute(db_change(
-                "insert into user_set (name, id, data) values (?, ?, ?)"
-            ), ['date', i[0], i[3]])
-            curs.execute(db_change(
-                "insert into user_set (name, id, data) values (?, ?, ?)"
-            ), ['encode', i[0], i[4]])
-            
-    if ver_num < 3400101:
-        # user_set이랑 user_application 테이블의 통합
-        curs.execute(db_change('' + \
-            'select id, pw, date, encode, question, answer, ip, ua, email ' + \
-            'from user_application' + \
-        ''))
-        for i in curs.fetchall():
-            sql_data = {}
-            sql_data['id'] = i[0]
-            sql_data['pw'] = i[1]
-            sql_data['date'] = i[2]
-            sql_data['encode'] = i[3]
-            sql_data['question'] = i[4]
-            sql_data['answer'] = i[5]
-            sql_data['ip'] = i[6]
-            sql_data['ua'] = i[7]
-            sql_data['email'] = i[8]
-            
-            curs.execute(db_change(
-                "insert into user_set (name, id, data) values (?, ?, ?)"
-            ), ['application', i[0], json.dumps(sql_data)])
-    
-    conn.commit()
-
-    print('Update completed')
-
-def set_init_always(ver_num):
-    curs = conn.cursor()
-
-    curs.execute(db_change('delete from other where name = "ver"'))
-    curs.execute(db_change('insert into other (name, data) values ("ver", ?)'), [ver_num])
-    
-    curs.execute(db_change('delete from alist where name = "owner"'))
-    curs.execute(db_change('insert into alist (name, acl) values ("owner", "owner")'))
-
-    if not os.path.exists(load_image_url()):
-        os.makedirs(load_image_url())
-    
-    conn.commit()
-    
-def set_init():
-    curs = conn.cursor()
-
-    # 초기값 설정 함수    
-    curs.execute(db_change("select html from html_filter where kind = 'email'"))
-    if not curs.fetchall():
-        for i in ['naver.com', 'gmail.com', 'daum.net', 'kakao.com']:
-            curs.execute(db_change(
-                "insert into html_filter (html, kind, plus, plus_t) values (?, 'email', '', '')"
-            ), [i])
-
-    curs.execute(db_change("select html from html_filter where kind = 'extension'"))
-    if not curs.fetchall():
-        for i in ['jpg', 'jpeg', 'png', 'gif', 'webp']:
-            curs.execute(db_change(
-                "insert into html_filter (html, kind, plus, plus_t) values (?, 'extension', '', '')"
-            ), [i])
-
-    curs.execute(db_change(
-        'select data from other ' + \
-        'where name = "smtp_server" or name = "smtp_port" or name = "smtp_security"'
-    ))
-    if not curs.fetchall():
-        for i in [
-            ['smtp_server', 'smtp.gmail.com'],
-            ['smtp_port', '587'], 
-            ['smtp_security', 'starttls']
-        ]:
-            curs.execute(db_change(
-                "insert into other (name, data) values (?, ?)"
-            ), [i[0], i[1]])
-            
-    curs.execute(db_change('select data from other where name = "key"'))
-    rep_data = curs.fetchall()
-    if not rep_data:
-        curs.execute(db_change('insert into other (name, data) values ("key", ?)'), [load_random_key()])
-
-    curs.execute(db_change('select data from other where name = "count_all_title"'))
-    if not curs.fetchall():
-        curs.execute(db_change('insert into other (name, data) values ("count_all_title", "0")'))
-        
-    conn.commit()
-
-# Func-simple
-## Func-simple-without_DB
-def get_default_admin_group():
-    return ['owner', 'ban']
-
-def load_random_key(long = 64):
-    return ''.join(
-        random.choice(
-            "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
-        ) for i in range(long)
-    )
-
-def http_warning():
-    return '''
-        <div id="http_warning_text"></div>
-        <script>
-            if(window.location.protocol !== 'https:') {
-                document.getElementById('http_warning_text').innerHTML = "''' + \
-                    load_lang('http_warning') + \
-                '''";
-                document.getElementById('http_warning_text').style.margin = "10px 0px 0px 0px";
-            }
-        </script>
-    '''
-
-def next_fix(link, num, page, end = 50):
-    list_data = ''
-
-    if num == 1:
-        if len(page) == end:
-            list_data += '' + \
-                '<hr class="main_hr">' + \
-                '<a href="' + link + str(num + 1) + '">(' + load_lang('next') + ')</a>' + \
-            ''
-    elif len(page) != end:
-        list_data += '' + \
-            '<hr class="main_hr">' + \
-            '<a href="' + link + str(num - 1) + '">(' + load_lang('previous') + ')</a>' + \
-        ''
-    else:
-        list_data += '' + \
-            '<hr class="main_hr">' + \
-            '<a href="' + link + str(num - 1) + '">(' + load_lang('previous') + ')</a> <a href="' + link + str(num + 1) + '">(' + load_lang('next') + ')</a>' + \
-        ''
-
-    return list_data
-
-def leng_check(A, B):
-    # B -> new
-    # A -> old
-    return '0' if A == B else (('-' + str(A - B)) if A > B else ('+' + str(B - A)))
-
-def number_check(data):
-    try:
-        int(data)
-        return data
-    except:
-        return '1'
-    
-def check_int(data):
-    try:
-        int(data)
-        return data
-    except:
-        return ''
-    
-def redirect(data = '/'):
-    return flask.redirect(flask.request.host_url[:-1] + data)
-    
-def get_acl_list(type_d = 'normal'):
-    if type_d == 'user':
-        return ['', 'user', 'all']
-    else:
-        return ['', 'all', 'user', 'admin', 'owner', '50_edit', 'email', 'ban', 'before', '30_day', 'ban_admin']
-
-## Func-simple-with_DB
-def load_image_url():
-    curs = conn.cursor()
-
-    curs.execute(db_change('select data from other where name = "image_where"'))
-    image_where = curs.fetchall()
-    image_where = image_where[0][0] if image_where else os.path.join('data', 'images')
-    
-    return image_where
-
-def load_domain():
-    curs = conn.cursor()
-
-    curs.execute(db_change("select data from other where name = 'domain'"))
-    domain = curs.fetchall()
-    domain = domain[0][0] if domain and domain[0][0] != '' else flask.request.host_url
-
-    return domain
-
-def edit_button(editor_display = '0'):
-    curs = conn.cursor()
-
-    insert_list = []
-
-    curs.execute(db_change("select html, plus from html_filter where kind = 'edit_top'"))
-    db_data = curs.fetchall()
-    for get_data in db_data:
-        insert_list += [[get_data[1], get_data[0]]]
-
-    data = ''
-    for insert_data in insert_list:
-        data += '' + \
-            '<a href="' + \
-                'javascript:do_insert_data(\'textarea_edit_view\', \'' + insert_data[0] + '\', ' + editor_display + ')' + \
-            '">(' + insert_data[1] + ')</a> ' + \
-        ''
-
-    data += (' ' if data != '' else '') + '<a href="/edit_top">(' + load_lang('add') + ')</a>'
-    data += '<hr class="main_hr">'
-    
-    return data
-
-def ip_warning():
-    curs = conn.cursor()
-
-    if ip_or_user() != 0:
-        curs.execute(db_change('select data from other where name = "no_login_warning"'))
-        data = curs.fetchall()
-        if data and data[0][0] != '':
-            text_data = '' + \
-                '<span>' + data[0][0] + '</span>' + \
-                '<hr class="main_hr">' + \
-            ''
-        else:
-            text_data = '' + \
-                '<span>' + load_lang('no_login_warning') + '</span>' + \
-                '<hr class="main_hr">' + \
-            ''
-    else:
-        text_data = ''
-
-    return text_data
-    
-# Func-login    
-def pw_encode(data, type_d = ''):
-    curs = conn.cursor()
-
-    if type_d == '':
-        curs.execute(db_change('select data from other where name = "encode"'))
-        set_data = curs.fetchall()
-
-        type_d = set_data[0][0]
-
-    if type_d == 'sha256':
-        return hashlib.sha256(bytes(data, 'utf-8')).hexdigest()
-    else:
-        if sys.version_info < (3, 6):
-            return sha3.sha3_256(bytes(data, 'utf-8')).hexdigest()
-        else:
-            return hashlib.sha3_256(bytes(data, 'utf-8')).hexdigest()
-
-def pw_check(data, data2, type_d = 'no', id_d = ''):
-    curs = conn.cursor()
-
-    curs.execute(db_change('select data from other where name = "encode"'))
-    db_data = curs.fetchall()
-
-    if type_d != 'no':
-        if type_d == '':
-            set_data = 'sha3'
-        else:
-            set_data = type_d
-    else:
-        set_data = db_data[0][0]
-
-    re_data = 1 if pw_encode(data, set_data) == data2 else 0
-    if db_data[0][0] != set_data and re_data == 1 and id_d != '':
-        curs.execute(db_change("update user_set set data = ? where id = ? and name = 'pw'"), [
-            pw_encode(data), 
-            id_d
-        ])
-        curs.execute(db_change("update user_set set data = ? where id = ? and name = 'encode'"), [
-            db_data[0][0], 
-            id_d
-        ])
-
-    return re_data
-        
-# Func-skin
-def easy_minify(data, tool = None):
-    # without_DB
-
-    return data
-
-def load_lang(data, safe = 0):
-    curs = conn.cursor()
-
-    global global_lang
-
-    ip = ip_check()
-    if ip_or_user(ip) == 0:
-        curs.execute(db_change('select data from user_set where name = "lang" and id = ?'), [ip])
-        rep_data = curs.fetchall()                    
-    elif 'lang' in flask.session:
-        rep_data = [[flask.session['lang']]]
-    else:
-        curs.execute(db_change("select data from other where name = 'language'"))
-        rep_data = curs.fetchall()
-
-    if not rep_data or rep_data[0][0] in ('', 'default'):
-        curs.execute(db_change("select data from other where name = 'language'"))
-        rep_data = curs.fetchall()
-
-    if rep_data:
-        lang_name = rep_data[0][0]
-    else:
-        lang_name = 'en-US'
-        
-    if lang_name in global_lang:
-        lang = global_lang[lang_name]
-    else:
-        lang_list = os.listdir('lang')
-        if (lang_name + '.json') in lang_list:
-            lang = json.loads(open(
-                os.path.join('lang', lang_name + '.json'), 
-                encoding = 'utf8'
-            ).read())
-            global_lang[lang_name] = lang
-        else:
-            lang = {}
-
-    if data in lang:
-        if safe == 1:
-            return lang[data] 
-        else:
-            return html.escape(lang[data])
-
-    return html.escape(data + ' (' + lang_name + ')')
-
-def skin_check(set_n = 0):
-    curs = conn.cursor()
-
-    # 개편 필요?
-    skin_list = load_skin('tenshi', 1)
-    skin = skin_list[0]
-    ip = ip_check()
-    
-    user_need_skin = ''
-    if ip_or_user(ip) == 0:
-        curs.execute(db_change('select data from user_set where name = "skin" and id = ?'), [ip])
-        skin_exist = curs.fetchall()
-        if skin_exist:
-            user_need_skin = skin_exist[0][0]            
-    else:
-        if 'skin' in flask.session:
-            user_need_skin = flask.session['skin']
-
-    if user_need_skin == '':
-        curs.execute(db_change('select data from other where name = "skin"'))
-        skin_exist = curs.fetchall()
-        if skin_exist:
-            user_need_skin = skin_exist[0][0]
-    
-    if user_need_skin != '' and user_need_skin in skin_list:
-        skin = user_need_skin
-
-    if set_n == 0:
-        return './views/' + skin + '/index.html'
-    else:
-        return skin
-    
-def wiki_css(data):
-    # without_DB
-
-    global data_css
-    global data_css_ver
-
-    data += ['' for _ in range(0, 3 - len(data))]
-
-    if data_css == '':
-        for i_data in os.listdir(os.path.join("views", "main_css", "css")):
-            if i_data != 'sub':
-                data_css += '<link rel="stylesheet" href="/views/main_css/css/' + i_data + '?ver=' + data_css_ver + '">'
-
-        for i_data in os.listdir(os.path.join("views", "main_css", "js")):
-            if i_data != 'sub':
-                data_css += '<script src="/views/main_css/js/' + i_data + '?ver=' + data_css_ver + '"></script>'
-                
-    data = data[0:2] + ['', '''
-        <link   rel="stylesheet"
-                href="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.2.0/build/styles/default.min.css">
-        <script src="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.2.0/build/highlight.min.js"></script>
-        <link   defer rel="stylesheet"
-                href="https://cdn.jsdelivr.net/npm/katex@0.13.2/dist/katex.min.css"
-                integrity="sha384-Cqd8ihRLum0CCg8rz0hYKPoLZ3uw+gES2rXQXycqnL5pgVQIflxAUDS7ZSjITLb5"
-                crossorigin="anonymous">
-        <script src="https://cdn.jsdelivr.net/npm/katex@0.13.2/dist/katex.min.js"
-                integrity="sha384-1Or6BdeNQb0ezrmtGeqQHFpppNd7a/gw29xeiSikBbsb44xu3uAo8c7FwbF5jhbd"
-                crossorigin="anonymous"></script>
-    ''' + data_css + '<script>window.addEventListener(\'DOMContentLoaded\', main_css_skin_load);</script>'] + data[2:]
-
-    return data
-
-def cut_100(data):
-    # without_DB
-
-    data = re.search(r'<pre style="display: none;" id="render_content_load">([^<>]+)<\/pre>', data)
-    if data:
-        data = data.group(1)
-        if len(data) > 100:
-            return data[0:100] + '...'
-        else:
-            return data[0:len(data)]
-    else:
-        return ''
-
-def wiki_set(num = 1):
-    curs = conn.cursor()
-
-    if num == 1:
-        skin_name = skin_check(1)
-        data_list = []
-
-        curs.execute(db_change('select data from other where name = ?'), ['name'])
-        db_data = curs.fetchall()
-        data_list += [db_data[0][0]] if db_data and db_data[0][0] != '' else ['Wiki']
-
-        curs.execute(db_change('select data from other where name = "license"'))
-        db_data = curs.fetchall()
-        data_list += [db_data[0][0]] if db_data and db_data[0][0] != '' else ['ARR']
-
-        data_list += ['', '']
-
-        curs.execute(db_change('select data from other where name = "logo" and coverage = ?'), [skin_name])
-        db_data = curs.fetchall()
-        if db_data and db_data[0][0] != '':
-            data_list += [db_data[0][0]]
-        else:
-            curs.execute(db_change('select data from other where name = "logo" and coverage = ""'))
-            db_data = curs.fetchall()
-            data_list += [db_data[0][0]] if db_data and db_data[0][0] != '' else [data_list[0]]
-
-        head_data = ''
-
-        curs.execute(db_change("select data from other where name = 'head' and coverage = ''"))
-        db_data = curs.fetchall()
-        head_data += db_data[0][0] if db_data and db_data[0][0] != '' else ''
-
-        curs.execute(db_change("select data from other where name = 'head' and coverage = ?"), [skin_name])
-        db_data = curs.fetchall()
-        head_data += db_data[0][0] if db_data and db_data[0][0] != '' else ''
-            
-        data_list += [head_data]
-    elif num == 2:
-        curs.execute(db_change('select data from other where name = "frontpage"'))
-        db_data = curs.fetchall()
-        data_list = db_data[0][0] if db_data and db_data[0][0] != '' else 'FrontPage'
-    elif num == 3:
-        curs.execute(db_change('select data from other where name = "upload"'))
-        db_data = curs.fetchall()
-        data_list = db_data[0][0] if db_data and db_data[0][0] != '' else '2'
-    else:
-        data_list = ''
-
-    return data_list
-
-def wiki_custom():
-    curs = conn.cursor()
-
-    ip = ip_check()
-    if ip_or_user(ip) == 0:
-        user_icon = 1
-        user_name = ip
-
-        curs.execute(db_change("select data from user_set where id = ? and name = 'custom_css'"), [ip])
-        user_head = curs.fetchall()
-        user_head = user_head[0][0] if user_head else ''
-        
-        curs.execute(db_change('select data from user_set where name = "email" and id = ?'), [ip])
-        email = curs.fetchall()
-        email = email[0][0] if email else ''
-
-        if admin_check('all') == 1:
-            user_admin = '1'
-            user_acl_list = []
-
-            curs.execute(db_change("select data from user_set where id = ? and name = 'acl'"), [ip])
-            curs.execute(db_change('select acl from alist where name = ?'), [curs.fetchall()[0][0]])
-            user_acl = curs.fetchall()
-            for i in user_acl:
-                user_acl_list += [i[0]]
-
-            user_acl_list = user_acl_list if user_acl != [] else '0'
-        else:
-            user_admin = '0'
-            user_acl_list = '0'
-
-        curs.execute(db_change("select count(*) from alarm where name = ?"), [ip])
-        count = curs.fetchall()
-        user_notice = str(count[0][0]) if count else '0'
-    else:
-        user_icon = 0
-        user_name = load_lang('user')
-        email = ''
-        user_admin = '0'
-        user_acl_list = '0'
-        user_notice = '0'
-        user_head = flask.session['head'] if 'head' in flask.session else ''
-
-    curs.execute(db_change("select title from rd where title = ? and stop = ''"), ['user:' + ip])
-    user_topic = '1' if curs.fetchall() else '0'
-    
-    split_path = flask.request.path.split('/')
-    if len(split_path) > 1:
-        split_path = split_path[1]
-    else:
-        split_path = 0
-
-    return [
-        '',
-        '',
-        user_icon,
-        user_head,
-        email,
-        user_name,
-        user_admin,
-        str(ban_check()),
-        user_notice,
-        user_acl_list,
-        ip,
-        user_topic,
-        split_path
-    ]
-
-def load_skin(data = '', set_n = 0, default = 0):
-    # without_DB
-
-    # data -> 가장 앞에 있을 스킨 이름
-    # set_n == 0 -> 스트링으로 반환
-    # set_n == 1 -> 리스트로 반환
-    # default == 0 -> 디폴트 미포함
-    # default == 1 -> 디폴트 포함
-
-    if set_n == 0:
-        skin_return_data = ''
-    else:
-        skin_return_data = []
-
-    skin_list_get = os.listdir('views')
-    if default == 1:
-        skin_list_get = ['default'] + skin_list_get
-
-    for skin_data in skin_list_get:
-        if skin_data != 'default':
-            see_data = skin_data
-        else:
-            see_data = load_lang('default')
-
-        if skin_data != 'main_css':
-            if set_n == 0:
-                if skin_data == data:
-                    skin_return_data = '' + \
-                        '<option value="' + skin_data + '">' + \
-                            see_data + \
-                        '</option>' + \
-                    '' + skin_return_data
-                else:
-                    skin_return_data += '' + \
-                        '<option value="' + skin_data + '">' + \
-                            see_data + \
-                        '</option>' + \
-                    ''
-            else:
-                if skin_data == data:
-                    skin_return_data = [skin_data] + skin_return_data
-                else:
-                    skin_return_data += [skin_data]                    
-
-    return skin_return_data
-
-# Func-markup
-def render_set(doc_name = '', doc_data = '', data_type = 'view', data_in = '', doc_acl = ''):
-    # without_DB
-
-    # data_type in ['view', 'raw', 'api_view', 'backlink']
-    doc_acl = acl_check(doc_name, 'render') if doc_acl == '' else doc_acl
-    doc_data = 0 if doc_data == None else doc_data
-        
-    if doc_acl == 1:
-        return 'HTTP Request 401.3'
-    else:
-        if data_type == 'raw':
-            return doc_data
-        else:
-            if doc_data != 0:
-                get_class_render = class_do_render(conn)
-                return get_class_render.do_render(doc_name, doc_data, data_type, data_in)
-            else:
-                return 'HTTP Request 404'
-
-# Func-request
-def send_email(who, title, data):
-    curs = conn.cursor()
-
-    try:
-        curs.execute(db_change('' + \
-            'select name, data from other ' + \
-            'where name = "smtp_email" or name = "smtp_pass" or name = "smtp_server" or name = "smtp_port" or name = "smtp_security"' + \
-        ''))
-        rep_data = curs.fetchall()
-
-        smtp_email = ''
-        smtp_pass = ''
-        smtp_server = ''
-        smtp_security = ''
-        smtp_port = ''
-        smtp = ''
-
-        for i in rep_data:
-            if i[0] == 'smtp_email':
-                smtp_email = i[1]
-            elif i[0] == 'smtp_pass':
-                smtp_pass = i[1]
-            elif i[0] == 'smtp_server':
-                smtp_server = i[1]
-            elif i[0] == 'smtp_security':
-                smtp_security = i[1]
-            elif i[0] == 'smtp_port':
-                smtp_port = i[1]
-        
-        smtp_port = int(smtp_port)
-        if smtp_security == 'plain':
-            smtp = smtplib.SMTP(smtp_server, smtp_port)
-        elif smtp_security == 'starttls':
-            smtp = smtplib.SMTP(smtp_server, smtp_port)
-            smtp.starttls()
-        else:
-            # if smtp_security == 'tls':
-            smtp = smtplib.SMTP_SSL(smtp_server, smtp_port)
-        
-        smtp.login(smtp_email, smtp_pass)
-
-        domain = load_domain()
-        wiki_name = wiki_set()[0]
-        
-        msg = email.mime.text.MIMEText(data)
-        msg['Subject'] = title
-        msg['From'] = 'openNAMU <noreply@' + domain + '>'
-        msg['To'] = who
-        
-        smtp.sendmail('openNAMU@' + domain, who, msg.as_string())
-        smtp.quit()
-
-        return 1
-    except Exception as e:
-        print('----')
-        print('Error : email send error')
-        print(e)
-
-        return 0
-
-def captcha_get():
-    curs = conn.cursor()
-
-    data = ''
-    
-    if ip_or_user() != 0:
-        curs.execute(db_change('select data from other where name = "recaptcha"'))
-        recaptcha = curs.fetchall()
-        
-        curs.execute(db_change('select data from other where name = "sec_re"'))
-        sec_re = curs.fetchall()
-        
-        curs.execute(db_change('select data from other where name = "recaptcha_ver"'))
-        rec_ver = curs.fetchall()
-        if  recaptcha and recaptcha[0][0] != '' and \
-            sec_re and sec_re[0][0] != '':
-            if not rec_ver or rec_ver[0][0] == '':
-                data += '' + \
-                    '<script src="https://www.google.com/recaptcha/api.js" async defer></script>' + \
-                    '<div class="g-recaptcha" data-sitekey="' + recaptcha[0][0] + '"></div>' + \
-                    '<hr class="main_hr">' + \
-                ''
-            else:
-                data += '' + \
-                    '<script src="https://www.google.com/recaptcha/api.js?render=' + recaptcha[0][0] + '"></script>' + \
-                    '<input type="hidden" id="g-recaptcha" name="g-recaptcha">' + \
-                    '<script type="text/javascript">' + \
-                        'grecaptcha.ready(function() {' + \
-                            'grecaptcha.execute(\'' + recaptcha[0][0] + '\', {action: \'homepage\'}).then(function(token) {' + \
-                                'document.getElementById(\'g-recaptcha\').value = token;' + \
-                            '});' + \
-                        '});' + \
-                    '</script>' + \
-                ''
-
-    return data
-
-def captcha_post(re_data, num = 1):
-    curs = conn.cursor()
-
-    if num == 1:
-        curs.execute(db_change('select data from other where name = "sec_re"'))
-        sec_re = curs.fetchall()
-        if  sec_re and sec_re[0][0] != '' and \
-            ip_or_user() != 0 and captcha_get() != '':
-            data = requests.get(
-                'https://www.google.com/recaptcha/api/siteverify' + \
-                '?secret=' + sec_re[0][0] + '&response=' + re_data
-            )
-            if data.status_code == 200:
-                json_data = json.loads(data.text)
-                if json_data['success'] != True:
-                    return 1
-
-        return 0
-
-# Func-user
-def ip_or_user(data = ''):
-    # without_DB
-
-    # 1 == ip
-    # 0 == reg
-    
-    if data == '':
-        data = ip_check()
-
-    if re.search(r'(\.|:)', data):
-        return 1
-    else:
-        return 0
-
-def admin_check(num = None, what = None, name = ''):
-    curs = conn.cursor()
-
-    ip = ip_check() if name == '' else name
-    time_data = get_time()
-    pass_ok = 0
-
-    if ip_or_user(ip) == 0:
-        curs.execute(db_change(
-            "select data from user_set where id = ? and name = 'acl'"
-        ), [ip])
-        user_auth = curs.fetchall()
-        if user_auth:
-            user_auth = user_auth[0][0]
-            
-            check = {
-                0 : 'owner',
-                1 : 'ban',
-                2 : 'nothing',
-                3 : 'toron',
-                4 : 'check',
-                5 : 'acl',
-                6 : 'hidel',
-                7 : 'give'
-            }
-            if not num:
-                check = check[0]
-            elif num == 'all':
-                check = [check[i] for i in check]
-            else:
-                check = check[num]
-
-            curs.execute(db_change(
-                'select name from alist where name = ? and acl = "owner"'
-            ), [user_auth])
-            if curs.fetchall():
-                pass_ok = 1
-            else:
-                if num == 'all':                    
-                    curs.execute(db_change(
-                        'select name from alist where name = ?'
-                    ), [user_auth])
-                else:
-                    curs.execute(db_change(
-                        'select name from alist where name = ? and acl = ?'
-                    ), [user_auth, check])
-                    
-                if curs.fetchall():
-                    pass_ok = 1
-
-                
-            if pass_ok == 1:
-                if what:
-                    curs.execute(db_change(
-                        "insert into re_admin (who, what, time) values (?, ?, ?)"
-                    ), [ip, what, time_data])
-                    conn.commit()
-
-                return 1
-
-    return 0
-
-def acl_check(name = 'test', tool = '', topic_num = '1'):
-    curs = conn.cursor()
-
-    ip = ip_check()
-    get_ban = ban_check()
-    acl_c = re.search(r"^user:((?:(?!\/).)*)", name) if name else None
-    if tool == '' and acl_c:
-        acl_n = acl_c.groups()
-
-        if get_ban == 1:
-            return 1
-
-        if admin_check(5) == 1:
-            return 0
-
-        curs.execute(db_change(
-            "select data from acl where title = ? and type = 'decu'"
-        ), ['user:' + acl_n[0]])
-        acl_data = curs.fetchall()
-        if acl_data:
-            if acl_data[0][0] == 'all':
-                return 0
-            elif acl_data[0][0] == 'user' and not ip_or_user(ip) == 1:
-                return 0
-            elif ip == acl_n[0] and not ip_or_user(ip) == 1:
-                return 0
-        else:
-            if ip == acl_n[0] and not ip_or_user(ip) == 1 and not ip_or_user(acl_n[0]) == 1:
-                return 0
-
-        return 1
-
-    if tool == 'topic':
-        if not name:
-            curs.execute(db_change("select title from rd where code = ?"), [topic_num])
-            name = curs.fetchall()
-            name = name[0][0] if name else 'test'
-        
-        end = 3
-    elif tool == 'render' or tool == '' or tool == 'vote':
-        if tool == '' and acl_check(name, 'render') == 1:
-            return 1
-
-        end = 2
-    else:
-        end = 1
-
-    for i in range(0, end):
-        if tool == '':
-            if i == 0:
-                curs.execute(db_change(
-                    "select data from acl where title = ? and type = 'decu'"
-                ), [name])
-            else:
-                curs.execute(db_change('select data from other where name = "edit"'))
-
-            num = 5
-        elif tool == 'topic':
-            if i == 0 and topic_num:
-                curs.execute(db_change("select acl from rd where code = ?"), [topic_num])
-            elif i == 1:
-                curs.execute(db_change(
-                    "select data from acl where title = ? and type = 'dis'"
-                ), [name])
-            else:
-                curs.execute(db_change('select data from other where name = "discussion"'))
-
-            num = 3
-        elif tool == 'upload':
-            curs.execute(db_change("select data from other where name = 'upload_acl'"))
-
-            num = 5
-        elif tool == 'many_upload':
-            curs.execute(db_change("select data from other where name = 'many_upload_acl'"))
-
-            num = 5
-        elif tool == 'vote':
-            if i == 0:
-                curs.execute(db_change(
-                    'select acl from vote where id = ? and user = ""'
-                ), [topic_num])
-            else:
-                curs.execute(db_change('select data from other where name = "vote_acl"'))
-
-            num = None
-        else:
-            # tool == 'render'
-            if i == 0:
-                curs.execute(db_change(
-                    "select data from acl where title = ? and type = 'view'"
-                ), [name])
-            else:
-                curs.execute(db_change("select data from other where name = 'all_view_acl'"))
-
-            num = 5
-
-        acl_data = curs.fetchall()
-        if  (
-                i == (end - 1) and \
-                (not acl_data or acl_data[0][0] == '' or acl_data[0][0] == 'normal')
-            ) and \
-            get_ban == 1 and \
-            tool != 'render':
-            return 1
-        elif acl_data and acl_data[0][0] != 'normal' and acl_data[0][0] != '':
-            if acl_data[0][0] != 'ban' and get_ban == 1 and tool != 'render':
-                return 1
-
-            if acl_data[0][0] == 'all' or acl_data[0][0] == 'ban':
-                return 0
-            elif acl_data[0][0] == 'user':
-                if ip_or_user(ip) != 1:
-                    return 0
-            elif acl_data[0][0] == 'admin':
-                if ip_or_user(ip) != 1:
-                    if admin_check(num) == 1:
-                        return 0
-            elif acl_data[0][0] == '50_edit':
-                if ip_or_user(ip) != 1:
-                    if admin_check(num) == 1:
-                        return 0
-                    else:
-                        curs.execute(db_change(
-                            "select count(*) from history where ip = ?"
-                        ), [ip])
-                        count = curs.fetchall()
-                        count = count[0][0] if count else 0
-                        if count >= 50:
-                            return 0
-            elif acl_data[0][0] == 'before':
-                if ip_or_user(ip) != 1:
-                    if admin_check(num) == 1:
-                        return 0
-                
-                curs.execute(db_change(
-                    "select ip from history where title = ? and ip = ?"
-                ), [name, ip])
-                if curs.fetchall():
-                    return 0
-            elif acl_data[0][0] == '30_day':
-                if ip_or_user(ip) != 1:
-                    if admin_check(num) == 1:
-                        return 0
-                    else:
-                        curs.execute(db_change(
-                            "select data from user_set where id = ? and name = 'date'"
-                        ), [ip])
-                        user_date = curs.fetchall()[0][0]
-                        
-                        time_1 = datetime.datetime.strptime(
-                            user_date, 
-                            '%Y-%m-%d %H:%M:%S'
-                        ) + datetime.timedelta(days = 30)
-                        time_2 = datetime.datetime.strptime(
-                            get_time(), 
-                            '%Y-%m-%d %H:%M:%S'
-                        )
-                        
-                        if time_2 > time_1:
-                            return 0
-            elif acl_data[0][0] == 'email':
-                if ip_or_user(ip) != 1:
-                    if admin_check(num) == 1:
-                        return 0
-                    else:
-                        curs.execute(db_change(
-                            "select data from user_set where id = ? and name = 'email'"
-                        ), [ip])
-                        if curs.fetchall():
-                            return 0
-            elif acl_data[0][0] == 'owner':
-                if admin_check() == 1:
-                    return 0
-            elif acl_data[0][0] == 'ban_admin':
-                if admin_check(1) == 1 or ban_check() == 1:
-                    return 0
-
-            return 1
-        else:
-            if i == (end - 1):
-                if tool == 'topic' and topic_num:
-                    curs.execute(db_change(
-                        "select title from rd where code = ? and stop != ''"
-                    ), [topic_num])
-                    if curs.fetchall():
-                        if admin_check(3, 'topic (code ' + topic_num + ')') == 1:
-                            return 0
-                    else:
-                        return 0
-                else:
-                    return 0
-
-    return 1
-
-def ban_check(ip = None, tool = ''):
-    curs = conn.cursor()
-
-    ip = ip_check() if not ip else ip
-    tool = '' if not tool else tool
-
-    if admin_check(None, None, ip) == 1:
-        return 0
-
-    curs.execute(db_change(
-        "update rb set ongoing = '' " + \
-        "where end < ? and end != '' and ongoing = '1'"
-    ), [get_time()])
-    conn.commit()
-
-    curs.execute(db_change("" + \
-        "select login, block from rb " + \
-        "where band = 'regex' and ongoing = '1'" + \
-    ""))
-    regex_d = curs.fetchall()
-    for test_r in regex_d:
-        g_regex = re.compile(test_r[1])
-        if g_regex.search(ip):
-            if tool == 'login':
-                if test_r[0] != 'O':
-                    return 1
-            else:
-                return 1
-
-    curs.execute(db_change("" + \
-        "select login from rb " + \
-        "where block = ? and band = '' and ongoing = '1'" + \
-        "" + \
-    ""), [ip])
-    ban_d = curs.fetchall()
-    if ban_d:
-        if tool == 'login':
-            if ban_d[0][0] != 'O':
-                return 1
-        else:
-            return 1
-
-    return 0
-
-def ip_pas(raw_ip, type_d = 0):
-    curs = conn.cursor()
-
-    hide = 0
-    end_ip = {}
-    i = 0
-
-    return_data = 0
-    if type(raw_ip) != type([]):
-        get_ip = [raw_ip]
-        
-        return_data = 1
-    else:
-        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 ''
-    ip_view = '' if admin_check(1) == 1 else ip_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 != '':
-            ip = re.sub(r'\.([^.]*)\.([^.]*)$', '.*.*', raw_ip)
-            ip = re.sub(r':([^:]*):([^:]*)$', ':*:*', ip)
-                
-            change_ip = 1
-        else:     
-            ip = raw_ip
-            
-        if type_d == 0:
-            if is_this_ip == 0:
-                ip = '<a href="/w/' + url_pas('user:' + raw_ip) + '">' + raw_ip + '</a>'
-                
-            if change_ip == 0:
-                ip += ' <a href="/user/' + url_pas(raw_ip) + '">(' + load_lang('tool') + ')</a>'
-
-        end_ip[raw_ip] = ip
-    
-    if return_data == 1:
-        return end_ip[raw_ip]
-    else:
-        return end_ip
-        
-# Func-edit
-def slow_edit_check():
-    curs = conn.cursor()
-
-    curs.execute(db_change("select data from other where name = 'slow_edit'"))
-    slow_edit = curs.fetchall()
-    if slow_edit and slow_edit != '0' and admin_check(5) != 1:
-        slow_edit = slow_edit[0][0]
-
-        curs.execute(db_change(
-            "select date from history where ip = ? order by date desc limit 1"
-        ), [ip_check()])
-        last_edit_data = curs.fetchall()
-        if last_edit_data:
-            last_edit_data = int(re.sub(' |:|-', '', last_edit_data[0][0]))
-            now_edit_data = int(
-                (datetime.datetime.now() - datetime.timedelta(
-                    seconds = int(slow_edit))
-                ).strftime("%Y%m%d%H%M%S")
-            )
-
-            if last_edit_data > now_edit_data:
-                return 1
-
-    return 0
-
-def edit_filter_do(data):
-    curs = conn.cursor()
-
-    if admin_check(1) != 1:
-        curs.execute(db_change(
-            "select plus, plus_t from html_filter where kind = 'regex_filter' and plus != ''"
-        ))
-        for data_list in curs.fetchall():
-            match = re.compile(data_list[0], re.I)
-            if match.search(data):
-                ban_insert(
-                    ip_check(),
-                    '0' if data_list[1] == 'X' else data_list[1],
-                    'edit filter',
-                    None,
-                    'tool:edit filter'
-                )
-
-                return 1
-
-    return 0
-
-# Func-insert
-def add_alarm(who, context):
-    curs = conn.cursor()
-
-    curs.execute(db_change(
-        'insert into alarm (name, data, date) values (?, ?, ?)'
-    ), [who, context, get_time()])
-    conn.commit()
-    
-def add_user(user_name, user_pw, user_email = '', user_encode = ''):
-    curs = conn.cursor()
-
-    if user_encode == '':
-        user_pw_hash = pw_encode(user_pw)
-
-        curs.execute(db_change('select data from other where name = "encode"'))
-        data_encode = curs.fetchall()
-        data_encode = data_encode[0][0]
-    else:
-        user_pw_hash = user_pw
-        data_encode = user_encode
-
-    curs.execute(db_change("select id from user_set limit 1"))
-    if not curs.fetchall():
-        user_auth = 'owner'
-    else:
-        user_auth = 'user'
-
-    curs.execute(db_change("insert into user_set (id, name, data) values (?, 'pw', ?)"), [
-        user_name,
-        user_pw_hash
-    ])
-    curs.execute(db_change("insert into user_set (id, name, data) values (?, 'acl', ?)"), [
-        user_name,
-        user_auth
-    ])
-    curs.execute(db_change("insert into user_set (id, name, data) values (?, 'date', ?)"), [
-        user_name,
-        get_time()
-    ])
-    curs.execute(db_change("insert into user_set (id, name, data) values (?, 'encode', ?)"), [
-        user_name,
-        data_encode
-    ])
-    
-    if user_email != '':
-        curs.execute(db_change("insert into user_set (name, id, data) values ('email', ?, ?)"), [
-            user_name,
-            user_email
-        ])
-        
-    conn.commit()
-    
-def ua_plus(u_id, u_ip, u_agent, time):
-    curs = conn.cursor()
-
-    curs.execute(db_change("select data from other where name = 'ua_get'"))
-    rep_data = curs.fetchall()
-    if rep_data and rep_data[0][0] != '':
-        pass
-    else:
-        curs.execute(db_change(
-            "insert into ua_d (name, ip, ua, today, sub) values (?, ?, ?, ?, '')"
-        ), [
-            u_id, 
-            u_ip, 
-            u_agent, 
-            time
-        ])
-        conn.commit()
-
-def ban_insert(name, end, why, login, blocker, type_d = None):
-    curs = conn.cursor()
-
-    now_time = get_time()
-    band = type_d if type_d else ''
-
-    curs.execute(db_change(
-        "update rb set ongoing = '' where end < ? and end != '' and ongoing = '1'"
-    ), [now_time])
-    curs.execute(db_change("" + \
-        "select block from rb " + \
-        "where ((end > ? and end != '') or end = '') and block = ? and " + \
-            "band = ? and ongoing = '1'" + \
-    ""), [now_time, name, band])
-    if curs.fetchall():
-        curs.execute(db_change(
-            "insert into rb (block, end, today, blocker, why, band) values (?, ?, ?, ?, ?, ?)"
-        ), [
-            name,
-            'release',
-            now_time,
-            blocker,
-            '',
-            band
-        ])
-        curs.execute(db_change(
-            "update rb set ongoing = '' where block = ? and band = ? and ongoing = '1'"
-        ), [name, band])
-    else:
-        login = 'O' if login != '' else ''
-
-        if end != '0':
-            end = int(number_check(end))
-            time = datetime.datetime.now()
-            plus = datetime.timedelta(seconds = end)
-            r_time = (time + plus).strftime("%Y-%m-%d %H:%M:%S")
-        else:
-            r_time = ''
-
-        curs.execute(db_change(
-            "insert into rb (block, end, today, blocker, why, band, ongoing, login) " + \
-            "values (?, ?, ?, ?, ?, ?, '1', ?)"
-        ), [
-            name, 
-            r_time, 
-            now_time, 
-            blocker, 
-            why, 
-            band,
-            login
-        ])
-
-    conn.commit()
-
-def rd_plus(topic_num, date, name = None, sub = None):
-    curs = conn.cursor()
-
-    curs.execute(db_change("select code from rd where code = ?"), [topic_num])
-    if curs.fetchall():
-        curs.execute(db_change("update rd set date = ? where code = ?"), [date, topic_num])
-    else:
-        curs.execute(db_change(
-            "insert into rd (title, sub, code, date) values (?, ?, ?, ?)"
-        ), [name, sub, topic_num, date])
-
-    conn.commit()
-
-def history_plus(title, data, date, ip, send, leng, t_check = '', mode = ''):
-    curs = conn.cursor()
-
-    if mode == 'add':
-        curs.execute(db_change(
-            "select id from history where title = ? order by id + 0 asc limit 1"
-        ), [title])
-        id_data = curs.fetchall()
-        id_data = str(int(id_data[0][0]) - 1) if id_data else '0'
-    else:
-        curs.execute(db_change(
-            "select id from history where title = ? order by id + 0 desc limit 1"
-        ), [title])
-        id_data = curs.fetchall()
-        id_data = str(int(id_data[0][0]) + 1) if id_data else '1'
-        
-        mode = mode if not re.search('^user:', title) else 'user'
-
-    send = re.sub(r'\(|\)|<|>', '', send)
-    send = send[:128] if len(send) > 128 else send
-    send = send + ' (' + t_check + ')' if t_check != '' else send
-
-    if mode != 'add' and mode != 'user':
-        curs.execute(db_change("select count(*) from rc where type = 'normal'"))
-        if curs.fetchall()[0][0] >= 200:
-            curs.execute(db_change(
-                "select id, title from rc where type = 'normal' order by date asc limit 1"
-            ))
-            rc_data = curs.fetchall()
-            if rc_data:
-                curs.execute(db_change(
-                    'delete from rc where id = ? and title = ? and type = "normal"'
-                ), [
-                    rc_data[0][0],
-                    rc_data[0][1]
-                ])
-    
-        curs.execute(db_change(
-            "insert into rc (id, title, date, type) values (?, ?, ?, 'normal')"
-        ), [
-            id_data,
-            title,
-            date
-        ])
-    
-    if mode != 'add':
-        curs.execute(db_change("select count(*) from rc where type = ?"), [mode])
-        if curs.fetchall()[0][0] >= 200:
-            curs.execute(db_change(
-                "select id, title from rc where type = ? order by date asc limit 1"
-            ), [mode])
-            rc_data = curs.fetchall()
-            if rc_data:
-                curs.execute(db_change(
-                    'delete from rc where id = ? and title = ? and type = ?'
-                ), [
-                    rc_data[0][0],
-                    rc_data[0][1],
-                    mode
-                ])
-    
-        curs.execute(db_change(
-            "insert into rc (id, title, date, type) values (?, ?, ?, ?)"
-        ), [
-            id_data,
-            title,
-            date,
-            mode
-        ])
-            
-    curs.execute(db_change(
-        "insert into history (id, title, data, date, ip, send, leng, hide, type) " + \
-        "values (?, ?, ?, ?, ?, ?, ?, '', ?)"
-    ), [
-        id_data,
-        title,
-        data,
-        date,
-        ip,
-        send,
-        leng,
-        mode
-    ])
-
-# Func-error
-def re_error(data):
-    curs = conn.cursor()
-
-    conn.commit()
-
-    if data == '/ban':
-        if ban_check() == 1:
-            end = '<div id="get_user_info"></div><script>load_user_info("' + ip_check() + '");</script>'
-        else:
-            end = '<ul class="inside_ul"><li>' + load_lang('authority_error') + '</li></ul>'
-
-        return easy_minify(flask.render_template(skin_check(),
-            imp = [load_lang('error'), wiki_set(1), wiki_custom(), wiki_css([0, 0])],
-            data = '<h2>' + load_lang('error') + '</h2>' + end,
-            menu = 0
-        )), 401
-    else:
-        num = int(number_check(data.replace('/error/', '')))
-        if num == 1:
-            data = load_lang('no_login_error')
-        elif num == 2:
-            data = load_lang('no_exist_user_error')
-        elif num == 3:
-            data = load_lang('authority_error')
-        elif num == 4:
-            data = load_lang('no_admin_block_error')
-        elif num == 5:
-            data = load_lang('skin_error')
-        elif num == 6:
-            data = load_lang('same_id_exist_error')
-        elif num == 7:
-            data = load_lang('long_id_error')
-        elif num == 8:
-            data = load_lang('id_char_error') + ' <a href="/name_filter">(' + load_lang('id_filter_list') + ')</a>'
-        elif num == 9:
-            data = load_lang('file_exist_error')
-        elif num == 10:
-            data = load_lang('password_error')
-        elif num == 11:
-            data = load_lang('topic_long_error')
-        elif num == 12:
-            data = load_lang('email_error')
-        elif num == 13:
-            data = load_lang('recaptcha_error')
-        elif num == 14:
-            data = load_lang('file_extension_error') + ' <a href="/extension_filter">(' + load_lang('extension_filter_list') + ')</a>'
-        elif num == 15:
-            data = load_lang('edit_record_error')
-        elif num == 16:
-            data = load_lang('same_file_error')
-        elif num == 17:
-            data = load_lang('file_capacity_error') + wiki_set(3)
-        elif num == 18:
-            data = load_lang('email_send_error')
-        elif num == 19:
-            data = load_lang('decument_exist_error')
-        elif num == 20:
-            data = load_lang('password_diffrent_error')
-        elif num == 21:
-            data = load_lang('edit_filter_error')
-        elif num == 22:
-            data = load_lang('file_name_error')
-        elif num == 23:
-            data = load_lang('regex_error')
-        elif num == 24:
-            curs.execute(db_change("select data from other where name = 'slow_edit'"))
-            slow_edit = curs.fetchall()
-            slow_edit = '' if not slow_edit else slow_edit[0][0]
-            data = load_lang('fast_edit_error') + slow_edit
-        elif num == 25:
-            data = load_lang('too_many_dec_error')
-        elif num == 26:
-            data = load_lang('application_not_found')
-        elif num == 27:
-            data = load_lang("invalid_password_error")
-        elif num == 28:
-            data = load_lang('watchlist_overflow_error')
-        elif num == 29:
-            data = load_lang('copyright_disagreed')
-        elif num == 30:
-            data = load_lang('ie_wrong_callback')
-        elif num == 33:
-            data = load_lang('restart_fail_error')
-        elif num == 34:
-            data = load_lang("update_error") + ' <a href="https://github.com/opennamu/opennamu">(Github)</a>'
-        elif num == 35:
-            data = load_lang('same_email_error')
-        elif num == 36:
-            data = load_lang('input_email_error')
-        else:
-            data = '???'
-
-        if num == 5:
-            if flask.request.path != '/main_skin_set':
-                title = load_lang('skin_set')
-                tool = [['main_skin_set', load_lang('main_skin_set')]]
-                load_skin_set = ''
-            else:
-                title = load_lang('main_skin_set')
-                tool = [['skin_set', load_lang('skin_set')]]
-                load_skin_set = '<script>main_css_skin_set();</script>'
-        
-            return easy_minify(flask.render_template(skin_check(),
-                imp = [title, wiki_set(1), wiki_custom(), wiki_css([0, 0])],
-                data = '' + \
-                    '<div id="main_skin_set">' + \
-                        '<h2>' + load_lang('error') + '</h2>' + \
-                        '<ul class="inside_ul">' + \
-                            '<li>' + data + ' <a href="/main_skin_set">(' + load_lang('main_skin_set') + ')</a></li>' + \
-                        '</ul>' + \
-                    '</div>' + \
-                    load_skin_set,
-                menu = tool
-            ))
-        else:
-            return easy_minify(flask.render_template(skin_check(),
-                imp = [load_lang('error'), wiki_set(1), wiki_custom(), wiki_css([0, 0])],
-                data = '' + \
-                     '<h2>' + load_lang('error') + '</h2>' + \
-                     '<ul class="inside_ul">' + \
-                         '<li>' + data + '</li>' + \
-                     '</ul>' + \
-                '',
-                menu = 0
-            )), 400

+ 8 - 21
route/tool/func_tool.py

@@ -32,27 +32,14 @@ def ip_check(d_type = 0):
     ip = ''
     if d_type == 0 and (flask.session and 'id' in flask.session):
         ip = flask.session['id']
-    else:    
-        for for_a in range(5):
-            if for_a == 0:
-                ip = flask.request.environ.get('HTTP_X_REAL_IP', '::1')
-            elif for_a == 1:
-                ip = flask.request.environ.get('HTTP_CLIENT_IP', '::1')
-            elif for_a == 2:
-                ip = flask.request.environ.get('HTTP_X_FORWARDED_FOR', '::1')
-            elif for_a == 3:
-                ip = flask.request.environ.get('HTTP_CF_CONNECTING_IP', '::1')
-            else:
-                ip = flask.request.environ.get('REMOTE_ADDR', '::1')
-            
-            if type(ip) == type([]):
-                ip = ip[0]
-            else:
-                ip = ip.split(',')
-                ip = ip[0]
-
-            if ip != '::1':
-                break
+    else:        
+        ip = flask.request.environ.get('HTTP_X_REAL_IP',
+            flask.request.environ.get('HTTP_CF_CONNECTING_IP',
+                flask.request.environ.get('REMOTE_ADDR',
+                    '::1'
+                )
+            )
+        )
 
     return ip
 

+ 1 - 1
route/topic.py

@@ -125,7 +125,7 @@ def topic(topic_num = 0):
                     <div id="top_topic"></div>
                     <div id="main_topic"></div>
                     <div id="plus_topic"></div>
-                    <script>new_topic_load("''' + topic_num + '''");</script>
+                    <script>opennamu_do_thread_make("''' + topic_num + '''");</script>
                     <a href="/thread/''' + topic_num + '/tool">(' + load_lang('topic_tool') + ''')</a>
                     <hr class="main_hr">
                     <form style="''' + display + '''" method="post">

+ 2 - 2
route/topic_close_list.py

@@ -40,9 +40,9 @@ def topic_close_list(name = 'Test'):
                 <div id="topic_pre_''' + data[0] + '''"></div>
                 <div id="topic_back_pre_''' + data[0] + '''"></div>
                 <script>
-                    new_topic_load(''' + data[0] + ', "list", "/normal/1", "topic_pre_' + data[0] + '''");
+                    opennamu_do_thread_make(''' + data[0] + ', "list", "/normal/1", "topic_pre_' + data[0] + '''");
                     if(''' + t_data[0][0] + ''' !== 1) {
-                        new_topic_load(''' + data[0] + ', "list", "/normal/' + t_data[0][0] + '", "topic_back_pre_' + data[0] + '''");
+                        opennamu_do_thread_make(''' + data[0] + ', "list", "/normal/' + t_data[0][0] + '", "topic_back_pre_' + data[0] + '''");
                     }
                 </script>
             '''

+ 175 - 0
route/user_challenge.py

@@ -0,0 +1,175 @@
+from .tool.func import *
+
+def do_make_challenge_design(img, title, info, disable = 0):
+    if disable == 1:
+        table_style = 'style="border: 2px solid green"'
+    else:
+        table_style = 'style="border: 2px solid red"'
+    
+    return '''
+        <table id="main_table_set" ''' + table_style + '''>
+            <tr>
+                <td id="main_table_width_quarter" rowspan="2">
+                    <span style="font-size: 64px;">''' + img + '''</span>
+                </td>
+                <td>
+                    <span style="font-size: 32px;">''' + title + '''</span>
+                </td>
+            </tr>
+            <tr>
+                <td>''' + info + '''</td>
+        </table>
+        <hr class="main_hr">
+    '''
+
+def user_challenge():
+    ip = ip_check()
+    if ip_or_user(ip) == 1:
+        return redirect('/user')
+    
+    with get_db_connect() as conn:
+        curs = conn.cursor()
+
+        data_html_green = ''
+        data_html_red = ''
+        
+        data_html_green += do_make_challenge_design(
+            '🆕',
+            load_lang('challenge_title_register'), 
+            load_lang('challenge_info_register'),
+            1
+        )
+        
+        curs.execute(db_change('select count(*) from history where ip = ?'), [ip])
+        db_data = curs.fetchall()
+        
+        disable = 1 if db_data[0][0] >= 1 else 0
+        data_html = do_make_challenge_design(
+            '✏',
+            load_lang('challenge_title_first_contribute'), 
+            load_lang('challenge_info_first_contribute'),
+            disable
+        )
+        if disable == 1:
+            data_html_green += data_html
+        else:
+            data_html_red += data_html
+        
+        disable = 1 if db_data[0][0] >= 10 else 0
+        data_html = do_make_challenge_design(
+            '🗊',
+            load_lang('challenge_title_tenth_contribute'), 
+            load_lang('challenge_info_tenth_contribute'),
+            disable
+        )
+        if disable == 1:
+            data_html_green += data_html
+        else:
+            data_html_red += data_html
+        
+        disable = 1 if db_data[0][0] >= 100 else 0
+        data_html = do_make_challenge_design(
+            '🗀',
+            load_lang('challenge_title_hundredth_contribute'), 
+            load_lang('challenge_info_hundredth_contribute'),
+            disable
+        )
+        if disable == 1:
+            data_html_green += data_html
+        else:
+            data_html_red += data_html
+        
+        disable = 1 if db_data[0][0] >= 1000 else 0
+        data_html = do_make_challenge_design(
+            '🖪',
+            load_lang('challenge_title_thousandth_contribute'), 
+            load_lang('challenge_info_thousandth_contribute'),
+            disable
+        )
+        if disable == 1:
+            data_html_green += data_html
+        else:
+            data_html_red += data_html
+        
+        disable = 1 if db_data[0][0] >= 10000 else 0
+        data_html = do_make_challenge_design(
+            '🖴',
+            load_lang('challenge_title_tenthousandth_contribute'), 
+            load_lang('challenge_info_tenthousandth_contribute'),
+            disable
+        )
+        if disable == 1:
+            data_html_green += data_html
+        else:
+            data_html_red += data_html
+        
+        curs.execute(db_change("select count(*) from topic where ip = ?"), [ip])
+        db_data = curs.fetchall()
+        
+        disable = 1 if db_data[0][0] >= 1 else 0
+        data_html = do_make_challenge_design(
+            '🗨',
+            load_lang('challenge_title_first_discussion'), 
+            load_lang('challenge_info_first_discussion'),
+            disable
+        )
+        if disable == 1:
+            data_html_green += data_html
+        else:
+            data_html_red += data_html
+        
+        disable = 1 if db_data[0][0] >= 10 else 0
+        data_html = do_make_challenge_design(
+            '🗪',
+            load_lang('challenge_title_tenth_discussion'), 
+            load_lang('challenge_info_tenth_discussion'),
+            disable
+        )
+        if disable == 1:
+            data_html_green += data_html
+        else:
+            data_html_red += data_html
+        
+        disable = 1 if db_data[0][0] >= 100 else 0
+        data_html = do_make_challenge_design(
+            '🖅',
+            load_lang('challenge_title_hundredth_discussion'), 
+            load_lang('challenge_info_hundredth_discussion'),
+            disable
+        )
+        if disable == 1:
+            data_html_green += data_html
+        else:
+            data_html_red += data_html
+        
+        disable = 1 if db_data[0][0] >= 1000 else 0
+        data_html = do_make_challenge_design(
+            '☏',
+            load_lang('challenge_title_thousandth_discussion'), 
+            load_lang('challenge_info_thousandth_discussion'),
+            disable
+        )
+        if disable == 1:
+            data_html_green += data_html
+        else:
+            data_html_red += data_html
+        
+        disable = 1 if db_data[0][0] >= 10000 else 0
+        data_html = do_make_challenge_design(
+            '🖧',
+            load_lang('challenge_title_tenthousandth_discussion'), 
+            load_lang('challenge_info_tenthousandth_discussion'),
+            disable
+        )
+        if disable == 1:
+            data_html_green += data_html
+        else:
+            data_html_red += data_html
+            
+        data_html = data_html_green + data_html_red
+        
+        return easy_minify(flask.render_template(skin_check(),
+            imp = [load_lang('challenge'), wiki_set(), wiki_custom(), wiki_css([0, 0])],
+            data = data_html,
+            menu = [['user', load_lang('return')]]
+        ))

+ 1 - 0
route/user_info.py

@@ -27,6 +27,7 @@ def user_info_2(conn, name):
 
             tool_menu += '<li><a href="/watch_list">' + load_lang('watchlist') + '</a></li>'
             tool_menu += '<li><a href="/star_doc">' + load_lang('star_doc') + '</a></li>'
+            tool_menu += '<li><a href="/challenge">' + load_lang('challenge') + '</a></li>'
             tool_menu += '<li><a href="/acl/user:' + url_pas(ip) + '">' + load_lang('user_document_acl') + '</a></li>'
         else:
             login_menu += '''

+ 19 - 2
route/user_setting.py

@@ -13,7 +13,8 @@ def user_setting_2(conn, server_set_var):
         if flask.request.method == 'POST':
             auto_list = [
                 ['skin', flask.request.form.get('skin', '')], 
-                ['lang', flask.request.form.get('lang', '')]
+                ['lang', flask.request.form.get('lang', '')],
+                ['user_title', flask.request.form.get('user_title', '')]
             ]
                 
             twofa_turn_on = 0 
@@ -49,7 +50,7 @@ def user_setting_2(conn, server_set_var):
             curs.execute(db_change('select data from user_set where name = "random_key" and id = ?'), [ip])
             data = curs.fetchall()
             ramdom_key = data[0][0] if data and data[0][0] != '' else '-'
-
+            
             curs.execute(db_change('select data from user_set where name = "skin" and id = ?'), [ip])
             data = curs.fetchall()
             div2 = load_skin(data[0][0] if data else '', 0, 1)
@@ -65,6 +66,18 @@ def user_setting_2(conn, server_set_var):
                     div3 = '<option value="' + lang_data + '">' + see_data + '</option>' + div3
                 else:
                     div3 += '<option value="' + lang_data + '">' + see_data + '</option>'
+            
+            # 여기 잘못 짬
+            curs.execute(db_change('select data from user_set where name = "user_title" and id = ?'), [ip])
+            data = curs.fetchall()
+            data = [['']] if not data else data
+            user_title_list = get_user_title_list()
+            div4 = ''
+            for user_title in user_title_list:                
+                if data and data[0][0] == user_title:
+                    div4 = '<option value="' + user_title + '">' + user_title_list[user_title] + '</option>' + div4
+                else:
+                    div4 += '<option value="' + user_title + '">' + user_title_list[user_title] + '</option>'
 
             curs.execute(db_change('select data from user_set where name = "2fa" and id = ?'), [ip])
             fa_data = curs.fetchall()
@@ -102,6 +115,10 @@ def user_setting_2(conn, server_set_var):
                         <span>''' + load_lang('language') + '''</span>
                         <hr class="main_hr">
                         <select name="lang">''' + div3 + '''</select>
+                        <hr class="main_hr">
+                        <span>''' + load_lang('user_title') + '''</span>
+                        <hr class="main_hr">
+                        <select name="user_title">''' + div4 + '''</select>
                         <h2>''' + load_lang('2fa') + '''</h2>
                         <select name="2fa"
                                 id="twofa_check_input"

+ 1 - 1
route/user_setting_email.py

@@ -12,7 +12,7 @@ def user_setting_email_2(conn):
         re_set_list = ['c_key']
         flask.session['c_key'] = load_random_key(32)
 
-        user_email = flask.request.form.get('email', '')
+        user_email = re.sub(r'\\', '', flask.request.form.get('email', ''))
         email_data = re.search(r'@([^@]+)$', user_email)
         if email_data:
             curs.execute(db_change("select html from html_filter where html = ? and kind = 'email'"), [email_data.group(1)])

+ 54 - 49
route/view_raw.py

@@ -1,61 +1,66 @@
 from .tool.func import *
 
-def view_raw_2(conn, name, topic_num, num):
-    curs = conn.cursor()
+def view_raw_2(name = None, topic_num = None, num = None, doc_acl = 0):
+    with get_db_connect() as conn:
+        curs = conn.cursor()
 
-    if acl_check(name, 'render') == 1:
-        return re_error('/ban')
+        if acl_check(name, 'render') == 1:
+            return re_error('/ban')
 
-    if topic_num:
-        topic_num = str(topic_num)
+        if topic_num:
+            topic_num = str(topic_num)
 
-    if not num:
-        num = flask.request.args.get('num', None)
         if num:
-            num = number_check(num)
-    else:
-        num = str(num)
+            num = str(num)
 
-    v_name = name
-    sub = ' (' + load_lang('raw') + ')'
+        v_name = name
+        p_data = ''
+        sub = ' (' + load_lang('raw') + ')'
 
-    if not topic_num and num:
-        curs.execute(db_change("select title from history where title = ? and id = ? and hide = 'O'"), [name, num])
-        if curs.fetchall() and admin_check(6) != 1:
-            return re_error('/error/3')
+        if not topic_num and num:
+            curs.execute(db_change("select title from history where title = ? and id = ? and hide = 'O'"), [name, num])
+            if curs.fetchall() and admin_check(6) != 1:
+                return re_error('/error/3')
 
-        curs.execute(db_change("select data from history where title = ? and id = ?"), [name, num])
+            curs.execute(db_change("select data from history where title = ? and id = ?"), [name, num])
 
-        sub += ' (r' + num + ')'
+            sub += ' (r' + num + ')'
 
-        menu = [['history/' + url_pas(name), load_lang('history')]]
-    elif topic_num:
-        if admin_check(6) != 1:
-            curs.execute(db_change("select data from topic where id = ? and code = ? and block = ''"), [num, topic_num])
+            menu = [['history/' + url_pas(name), load_lang('history')]]
+        elif topic_num:
+            if admin_check(6) != 1:
+                curs.execute(db_change("select data from topic where id = ? and code = ? and block = ''"), [num, topic_num])
+            else:
+                curs.execute(db_change("select data from topic where id = ? and code = ?"), [num, topic_num])
+
+            v_name = load_lang('discussion_raw')
+            sub = ' (#' + num + ')'
+
+            menu = [
+                ['thread/' + topic_num + '#' + num, load_lang('discussion')], 
+                ['thread/' + topic_num + '/admin/' + num, load_lang('return')]
+            ]
+        else:
+            curs.execute(db_change("select data from data where title = ?"), [name])
+
+            menu = [['w/' + url_pas(name), load_lang('return')]]
+
+        data = curs.fetchall()
+        if data:
+            p_data += '<textarea readonly rows="25">' + html.escape(data[0][0]) + '</textarea>'
+            
+            if doc_acl == 1:
+                p_data = '' + \
+                    load_lang('authority_error') + \
+                    '<hr class="main_hr">' + \
+                    p_data
+                ''
+                sub = ' (' + load_lang('edit') + ')'
+
+            return easy_minify(flask.render_template(skin_check(),
+                imp = [v_name, wiki_set(), wiki_custom(), wiki_css([sub, 0])],
+                data = p_data,
+                menu = menu
+            ))
         else:
-            curs.execute(db_change("select data from topic where id = ? and code = ?"), [num, topic_num])
-
-        v_name = load_lang('discussion_raw')
-        sub = ' (#' + num + ')'
-
-        menu = [
-            ['thread/' + topic_num + '#' + num, load_lang('discussion')], 
-            ['thread/' + topic_num + '/admin/' + num, load_lang('return')]
-        ]
-    else:
-        curs.execute(db_change("select data from data where title = ?"), [name])
-
-        menu = [['w/' + url_pas(name), load_lang('return')]]
-
-    data = curs.fetchall()
-    if data:
-        p_data = html.escape(data[0][0])
-        p_data = '<textarea readonly rows="25">' + p_data + '</textarea>'
-
-        return easy_minify(flask.render_template(skin_check(),
-            imp = [v_name, wiki_set(), wiki_custom(), wiki_css([sub, 0])],
-            data = p_data,
-            menu = menu
-        ))
-    else:
-        return re_error('/error/3')
+            return re_error('/error/3')

+ 69 - 54
route/vote_add.py

@@ -1,62 +1,77 @@
 from .tool.func import *
 
-def vote_add_2(conn):
-    curs = conn.cursor()
+def vote_add():
+    with get_db_connect() as conn:
+        curs = conn.cursor()
 
-    if admin_check() != 1:
-        return re_error('/ban')
-
-    if flask.request.method == 'POST':
-        vote_data = flask.request.form.get('data', 'test\ntest_2')
-        if vote_data.count('\n') < 1:
+        if admin_check() != 1:
             return re_error('/ban')
 
-        curs.execute(db_change('select id from vote order by id + 0 desc limit 1'))
-        id_data = curs.fetchall()
-        id_data = str((int(id_data[0][0]) + 1) if id_data else 1)
+        if flask.request.method == 'POST':
+            vote_data = flask.request.form.get('data', 'test\ntest_2')
+            if vote_data.count('\n') < 1:
+                return re_error('/ban')
+
+            curs.execute(db_change('select id from vote where not type = "option" order by id + 0 desc limit 1'))
+            id_data = curs.fetchall()
+            id_data = str((int(id_data[0][0]) + 1) if id_data else 1)
+
+            admin_check(None, 'add vote ' + id_data)
 
-        admin_check(None, 'add vote ' + id_data)
+            if flask.request.form.get('open_select', 'N') == 'Y':
+                open_data = 'open'
+            else:
+                open_data = 'n_open'
 
-        if flask.request.form.get('open_select', 'N') == 'Y':
-            open_data = 'open'
+            curs.execute(db_change("insert into vote (name, id, subject, data, user, type, acl) values (?, ?, ?, ?, '', ?, ?)"), [
+                flask.request.form.get('name', 'test'),
+                id_data,
+                flask.request.form.get('subject', 'test'),
+                flask.request.form.get('data', 'test'),
+                open_data,
+                flask.request.form.get('acl_select', '')
+            ])
+            
+            time_limitless = flask.request.form.get('limitless', '')
+            if time_limitless == '':
+                time_limit = flask.request.form.get('date', '')
+                if re.search(r'^[0-9]{4}-[0-9]{2}-[0-9]{2}$', time_limit):
+                    curs.execute(db_change("insert into vote (name, id, subject, data, user, type, acl) values ('end_date', ?, '', ?, '', 'option', '')"), [
+                        id_data,
+                        time_limit
+                    ])
+                    
+            conn.commit()
+
+            return redirect('/vote')
         else:
-            open_data = 'n_open'
-
-        curs.execute(db_change("insert into vote (name, id, subject, data, user, type, acl) values (?, ?, ?, ?, '', ?, ?)"), [
-            flask.request.form.get('name', 'test'),
-            id_data,
-            flask.request.form.get('subject', 'test'),
-            flask.request.form.get('data', 'test'),
-            open_data,
-            flask.request.form.get('acl_select', '')
-        ])
-        conn.commit()
-
-        return redirect('/vote')
-    else:
-        acl_data = '<select name="acl_select">'
-        acl_list = get_acl_list()
-        for data_list in acl_list:
-            acl_data += '<option value="' + data_list + '">' + (data_list if data_list != '' else 'normal') + '</option>'
-
-        acl_data += '</select>'
-
-        return easy_minify(flask.render_template(skin_check(),
-            imp = [load_lang('add_vote'), wiki_set(), wiki_custom(), wiki_css([0, 0])],
-            data = '' + \
-                '<form method="post">' + \
-                    '<input name="name" placeholder="' + load_lang('name') + '">' + \
-                    '<hr class="main_hr">' + \
-                    '<textarea rows="3" name="subject" placeholder="' + load_lang('explanation') + '"></textarea>' + \
-                    '<hr class="main_hr">' + \
-                    '<textarea rows="10" name="data" placeholder="' + load_lang('1_line_1_q') + '"></textarea>' + \
-                    '<hr class="main_hr">' + \
-                    '<input type="checkbox" value="Y" name="open_select"> ' + load_lang('open_vote') + \
-                    '<h2>' + load_lang('acl') + '</h2>' + \
-                    acl_data + ' <a href="/acl/TEST#exp">(' + load_lang('explanation') + ')</a>' + \
-                    '<hr class="main_hr">' + \
-                    '<button type="submit">' + load_lang('send') + '</buttom>' + \
-                '</form>' + \
-            '',
-            menu = [['vote', load_lang('return')]]
-        ))
+            acl_data = '<select name="acl_select">'
+            acl_list = get_acl_list()
+            for data_list in acl_list:
+                acl_data += '<option value="' + data_list + '">' + (data_list if data_list != '' else 'normal') + '</option>'
+
+            acl_data += '</select>'
+
+            return easy_minify(flask.render_template(skin_check(),
+                imp = [load_lang('add_vote'), wiki_set(), wiki_custom(), wiki_css([0, 0])],
+                data = '' + \
+                    '<form method="post">' + \
+                        '<input name="name" placeholder="' + load_lang('name') + '">' + \
+                        '<hr class="main_hr">' + \
+                        '<textarea rows="3" name="subject" placeholder="' + load_lang('explanation') + '"></textarea>' + \
+                        '<hr class="main_hr">' + \
+                        '<textarea rows="10" name="data" placeholder="' + load_lang('1_line_1_q') + '"></textarea>' + \
+                        '<hr class="main_hr">' + \
+                        '<input type="checkbox" value="Y" name="open_select"> ' + load_lang('open_vote') + \
+                        '<h2>' + load_lang('period') + '</h2>'
+                        '<input type="date" name="date" pattern="\d{4}-\d{2}-\d{2}">' + \
+                        '<hr class="main_hr">' + \
+                        '<input type="checkbox" value="Y" name="limitless"> ' + load_lang('limitless') + \
+                        '<h2>' + load_lang('acl') + '</h2>' + \
+                        acl_data + ' <a href="/acl/TEST#exp">(' + load_lang('explanation') + ')</a>' + \
+                        '<hr class="main_hr">' + \
+                        '<button type="submit">' + load_lang('send') + '</buttom>' + \
+                    '</form>' + \
+                '',
+                menu = [['vote', load_lang('return')]]
+            ))

+ 27 - 24
route/vote_close.py

@@ -1,29 +1,32 @@
 from .tool.func import *
 
-def vote_close_2(conn, num):
-    curs = conn.cursor()
+def vote_close(num = 1):
+    num = str(num)
+    
+    with get_db_connect() as conn:
+        curs = conn.cursor()
 
-    if admin_check() != 1:
-        return re_error('/ban')
+        if admin_check() != 1:
+            return re_error('/ban')
 
-    curs.execute(db_change('select type from vote where id = ? and user = ""'), [num])
-    data_list = curs.fetchall()
-    if not data_list:
-        return redirect('/vote')
-        
-    if data_list[0][0] == 'close':
-        type_set = 'open'
-    elif data_list[0][0] == 'n_close':
-        type_set = 'n_open'
-    elif data_list[0][0] == 'open':
-        type_set = 'close'
-    else:
-        type_set = 'n_close'
-        
-    curs.execute(db_change("update vote set type = ? where user = '' and id = ?"), [type_set, num])
-    conn.commit()
+        curs.execute(db_change('select type from vote where id = ? and user = ""'), [num])
+        data_list = curs.fetchall()
+        if not data_list:
+            return redirect('/vote')
 
-    if data_list[0][0] == 'close' or data_list[0][0] == 'n_close':
-        return redirect('/vote')
-    else:
-        return redirect('/vote?close=y')
+        if data_list[0][0] == 'close':
+            type_set = 'open'
+        elif data_list[0][0] == 'n_close':
+            type_set = 'n_open'
+        elif data_list[0][0] == 'open':
+            type_set = 'close'
+        else:
+            type_set = 'n_close'
+
+        curs.execute(db_change("update vote set type = ? where user = '' and id = ?"), [type_set, num])
+        conn.commit()
+
+        if data_list[0][0] == 'close' or data_list[0][0] == 'n_close':
+            return redirect('/vote')
+        else:
+            return redirect('/vote/list/close')

+ 46 - 44
route/vote_end.py

@@ -1,47 +1,49 @@
 from .tool.func import *
 
-def vote_end_2(conn, num):
-    curs = conn.cursor()
-
-    curs.execute(db_change('select name, subject, data, type from vote where id = ? and user = ""'), [num])
-    data_list = curs.fetchall()
-    if not data_list:
-        return redirect('/vote')
-
-    data = '' + \
-        '<h2>' + data_list[0][0] + '</h2>' + \
-        '<b>' + data_list[0][1] + '</b>' + \
-    ''
-
-    if admin_check() == 1:
-        if data_list[0][3] == 'open' or data_list[0][3] == 'n_open':
-            data += '' + \
-                '<hr class="main_hr">' + \
-                '<a href="/vote/close/' + num + '">(' + load_lang('close_vote') + ')</a>' + \
-            ''
-        else:
-            data += '' + \
-                '<hr class="main_hr">' + \
-                '<a href="/vote/close/' + num + '">(' + load_lang('re_open_vote') + ')</a>' + \
-            ''
-
-    vote_data = re.findall(r'([^\n]+)', data_list[0][2].replace('\r\n', '\n'))
-    for i in range(0, len(vote_data)):
-        data += '<h2>' + vote_data[i] + '</h2>'
-        data += '<ul class="inside_ul">'
+def vote_end(num = 1):
+    num = str(num)
+    
+    with get_db_connect() as conn:
+        curs = conn.cursor()
+
+        curs.execute(db_change('select name, subject, data, type from vote where id = ? and user = ""'), [num])
+        data_list = curs.fetchall()
+        if not data_list:
+            return redirect('/vote')
         
-        curs.execute(db_change('select user from vote where id = ? and user != "" and data = ?'), [num, str(i)])
-        data_list_2 = curs.fetchall()
-        if data_list[0][3] == 'open' or data_list[0][3] == 'close':
-            all_ip = ip_pas([j[0] for j in data_list_2])
-            for j in data_list_2:
-                data += '<li>' + all_ip[j[0]] + '</li>'
-
-        data += '<li>' + load_lang('result') + ' : ' + str(len(data_list_2)) + '</li>'
-        data += '</ul>'
-
-    return easy_minify(flask.render_template(skin_check(),
-        imp = [load_lang('result_vote'), wiki_set(), wiki_custom(), wiki_css([0, 0])],
-        data = data,
-        menu = [['vote', load_lang('return')]]
-    ))
+        curs.execute(db_change('select data from vote where id = ? and name = "end_date" and type = "option"'), [num])
+        db_data = curs.fetchall()
+        time_limit = ''
+        if db_data:
+            time_limit = db_data[0][0]
+
+        data = '<h2>' + data_list[0][0] + '</h2>'
+        data += '<b>' + data_list[0][1] + '</b><hr class="main_hr">' if data_list[0][1] != '' else ''
+        data += '<span>~ ' + time_limit + '</span><hr class="main_hr">' if time_limit != '' else ''
+
+        if admin_check() == 1:
+            if data_list[0][3] == 'open' or data_list[0][3] == 'n_open':
+                data += '<a href="/vote/close/' + num + '">(' + load_lang('close_vote') + ')</a>'
+            else:
+                data += '<a href="/vote/close/' + num + '">(' + load_lang('re_open_vote') + ')</a>'
+
+        vote_data = re.findall(r'([^\n]+)', data_list[0][2].replace('\r\n', '\n'))
+        for i in range(0, len(vote_data)):
+            data += '<h2>' + vote_data[i] + '</h2>'
+            data += '<ul class="inside_ul">'
+
+            curs.execute(db_change('select user from vote where id = ? and user != "" and data = ?'), [num, str(i)])
+            data_list_2 = curs.fetchall()
+            if data_list[0][3] == 'open' or data_list[0][3] == 'close':
+                all_ip = ip_pas([j[0] for j in data_list_2])
+                for j in data_list_2:
+                    data += '<li>' + all_ip[j[0]] + '</li>'
+
+            data += '<li>' + load_lang('result') + ' : ' + str(len(data_list_2)) + '</li>'
+            data += '</ul>'
+
+        return easy_minify(flask.render_template(skin_check(),
+            imp = [load_lang('result_vote'), wiki_set(), wiki_custom(), wiki_css([0, 0])],
+            data = data,
+            menu = [['vote', load_lang('return')]]
+        ))

+ 33 - 32
route/vote_list.py

@@ -1,40 +1,41 @@
 from .tool.func import *
 
-def vote_list_2(conn, list_type, num):
-    curs = conn.cursor()
+def vote_list(list_type = 'normal', num = 1):    
+    with get_db_connect() as conn:
+        curs = conn.cursor()
 
-    sql_num = (num * 50 - 50) if num * 50 > 0 else 0
+        sql_num = (num * 50 - 50) if num * 50 > 0 else 0
 
-    data = ''
-    if list_type == 'normal':
-        data += '<a href="/vote/list/close">(' + load_lang('close_vote_list') + ')</a>'
-        sub = 0
-        curs.execute(db_change('select name, id, type from vote where type = "open" or type = "n_open" limit ?, 50'), [sql_num])
-    else:
-        data += '<a href="/vote">(' + load_lang('open_vote_list') + ')</a>'
-        sub = '(' + load_lang('closed') + ')'
-        curs.execute(db_change('select name, id, type from vote where type = "close" or type = "n_close" limit ?, 50'), [sql_num])
+        data = ''
+        if list_type == 'normal':
+            data += '<a href="/vote/list/close">(' + load_lang('close_vote_list') + ')</a>'
+            sub = 0
+            curs.execute(db_change('select name, id, type from vote where type = "open" or type = "n_open" limit ?, 50'), [sql_num])
+        else:
+            data += '<a href="/vote">(' + load_lang('open_vote_list') + ')</a>'
+            sub = '(' + load_lang('closed') + ')'
+            curs.execute(db_change('select name, id, type from vote where type = "close" or type = "n_close" limit ?, 50'), [sql_num])
+
+        data += '<ul class="inside_ul">'
 
-    data += '<ul class="inside_ul">'
+        data_list = curs.fetchall()
+        for i in data_list:
+            if list_type == 'normal':
+                open_select = load_lang('open_vote') if i[2] == 'open' else load_lang('not_open_vote')
+            else:
+                open_select = load_lang('open_vote') if i[2] == 'close' else load_lang('not_open_vote')
 
-    data_list = curs.fetchall()
-    for i in data_list:
+            data += '<li><a href="/vote/' + i[1] + '">' + html.escape(i[0]) + '</a> (' + open_select + ')</li>'
+
+        data += '</ul>'
         if list_type == 'normal':
-            open_select = load_lang('open_vote') if i[2] == 'open' else load_lang('not_open_vote')
+            data += ('<a href="/vote/add">(' + load_lang('add_vote') + ')</a>') if admin_check() == 1 else ''
+            data += next_fix('/vote/list/', num, data_list)
         else:
-            open_select = load_lang('open_vote') if i[2] == 'close' else load_lang('not_open_vote')
-
-        data += '<li><a href="/vote/' + i[1] + '">' + html.escape(i[0]) + '</a> (' + open_select + ')</li>'
-
-    data += '</ul>'
-    if list_type == 'normal':
-        data += ('<a href="/vote/add">(' + load_lang('add_vote') + ')</a>') if admin_check() == 1 else ''
-        data += next_fix('/vote/list/', num, data_list)
-    else:
-        data += next_fix('/vote/list/close/', num, data_list)
-
-    return easy_minify(flask.render_template(skin_check(),
-        imp = [load_lang('vote_list'), wiki_set(), wiki_custom(), wiki_css([sub, 0])],
-        data = data,
-        menu = [['other', load_lang('return')]]
-    ))
+            data += next_fix('/vote/list/close/', num, data_list)
+
+        return easy_minify(flask.render_template(skin_check(),
+            imp = [load_lang('vote_list'), wiki_set(), wiki_custom(), wiki_css([sub, 0])],
+            data = data,
+            menu = [['other', load_lang('return')]]
+        ))

+ 65 - 52
route/vote_select.py

@@ -1,66 +1,79 @@
 from .tool.func import *
 
-def vote_select_2(conn, num):
-    curs = conn.cursor()
+def vote_select(num = 1):
+    num = str(num)
+    
+    with get_db_connect() as conn:
+        curs = conn.cursor()
 
-    curs.execute(db_change('select name, subject, data, type from vote where id = ? and user = ""'), [num])
-    data_list = curs.fetchall()
-    if not data_list:
-        return redirect('/vote')
+        curs.execute(db_change('select name, subject, data, type from vote where id = ? and user = ""'), [num])
+        data_list = curs.fetchall()
+        if not data_list:
+            return redirect('/vote')
 
-    if data_list[0][3] == 'close' or data_list[0][3] == 'n_close':
-        return redirect('/vote/end/' + num)
+        if data_list[0][3] == 'close' or data_list[0][3] == 'n_close':
+            return redirect('/vote/end/' + num)
 
-    if acl_check('', 'vote', num) == 1:
-        return redirect('/vote/end/' + num)
+        if acl_check('', 'vote', num) == 1:
+            return redirect('/vote/end/' + num)
 
-    curs.execute(db_change('select user from vote where id = ? and user = ?'), [num, ip_check()])
-    if curs.fetchall():
-        return redirect('/vote/end/' + num)
+        curs.execute(db_change('select user from vote where id = ? and user = ?'), [num, ip_check()])
+        if curs.fetchall():
+            return redirect('/vote/end/' + num)
+        
+        curs.execute(db_change('select data from vote where id = ? and name = "end_date" and type = "option"'), [num])
+        db_data = curs.fetchall()
+        time_limit = ''
+        if db_data:
+            time_limit = db_data[0][0]
+            
+            time_db = int(db_data[0][0].split()[0].replace('-', ''))
+            time_today = int(get_time().split()[0].replace('-', ''))
+            
+            if time_today > time_db:
+                return redirect('/vote/end/' + num)
 
-    vote_data = re.findall(r'([^\n]+)', data_list[0][2].replace('\r\n', '\n'))
+        vote_data = re.findall(r'([^\n]+)', data_list[0][2].replace('\r\n', '\n'))
 
-    if flask.request.method == 'POST':
-        try:
-            vaild_check = int(flask.request.form.get('vote_data', '0'))
-        except:
-            return redirect('/vote/' + num)
+        if flask.request.method == 'POST':
+            try:
+                vaild_check = int(flask.request.form.get('vote_data', '0'))
+            except:
+                return redirect('/vote/' + num)
 
-        if len(vote_data) - 1 < vaild_check:
-            return redirect('/vote/' + num)
+            if len(vote_data) - 1 < vaild_check:
+                return redirect('/vote/' + num)
 
-        curs.execute(db_change("insert into vote (name, id, subject, data, user, type) values ('', ?, '', ?, ?, 'select')"), [
-            num,
-            str(vaild_check),
-            ip_check()
-        ])
-        conn.commit()
+            curs.execute(db_change("insert into vote (name, id, subject, data, user, type) values ('', ?, '', ?, ?, 'select')"), [
+                num,
+                str(vaild_check),
+                ip_check()
+            ])
+            conn.commit()
 
-        return redirect('/vote/end/' + num)
-    else:
-        data = '' + \
-            '<h2>' + data_list[0][0] + '</h2>' + \
-            '<b>' + data_list[0][1] + '</b>' + \
-            '<hr class="main_hr">' + \
-        ''
+            return redirect('/vote/end/' + num)
+        else:
+            data = '<h2>' + data_list[0][0] + '</h2>'
+            data += '<b>' + data_list[0][1] + '</b><hr class="main_hr">' if data_list[0][1] != '' else ''
+            data += '<span>~ ' + time_limit + '</span><hr class="main_hr">' if time_limit != '' else ''
 
-        select_data = '<select name="vote_data">'
-        line_num = 0
-        for i in vote_data:
-            select_data += '<option value="' + str(line_num) + '">' + i + '</option>'
-            line_num += 1
+            select_data = '<select name="vote_data">'
+            line_num = 0
+            for i in vote_data:
+                select_data += '<option value="' + str(line_num) + '">' + i + '</option>'
+                line_num += 1
 
-        select_data += '</select>'
-        data += '' + \
-            '<form method="post">' + \
-                select_data + \
-                '<hr class="main_hr">' + \
-                '<button type="submit">' + load_lang('send') + '</buttom>' + \
-            '</form>' + \
-        ''
+            select_data += '</select>'
+            data += '' + \
+                '<form method="post">' + \
+                    select_data + \
+                    '<hr class="main_hr">' + \
+                    '<button type="submit">' + load_lang('send') + '</buttom>' + \
+                '</form>' + \
+            ''
 
-        return easy_minify(flask.render_template(skin_check(),
-            imp = [load_lang('vote'), wiki_set(), wiki_custom(), wiki_css([0, 0])],
-            data = data,
-            menu = [['vote', load_lang('return')], ['end_vote/' + num, load_lang('result')]]
-        ))
+            return easy_minify(flask.render_template(skin_check(),
+                imp = [load_lang('vote'), wiki_set(), wiki_custom(), wiki_css([0, 0])],
+                data = data,
+                menu = [['vote', load_lang('return')], ['vote/end/' + num, load_lang('result')]]
+            ))

+ 1 - 1
version.json

@@ -1,6 +1,6 @@
 {
     "beta" : {
-        "r_ver" : "v3.4.3 (stable3) (beta21) (dev38)",
+        "r_ver" : "v3.4.4 (stable1) (beta1) (dev6)",
         "c_ver" : "3500101",
         "s_ver" : "3500110"
     }

+ 6 - 2
views/main_css/css/main.css

@@ -120,7 +120,7 @@ a {
 }
 
 /* 위키 내용 관련 */
-#toc {
+#toc, .opennamuTOC {
     border: 1px solid gainsboro;
     padding: 20px;
     
@@ -146,7 +146,7 @@ pre {
     white-space: pre-wrap;
 }
 
-#toc_title {
+#toc_title, .opennamuTOCtitle {
     font-size: 1.2rem;
 }
 
@@ -188,6 +188,10 @@ hr {
     line-break: anywhere;
 }
 
+.render_content_load {
+    display: none;
+}
+
 blockquote {
     padding: 15px 40px 15px 15px;
     margin: 15px 0 0;

+ 13 - 0
views/main_css/js/func/func.js

@@ -0,0 +1,13 @@
+"use strict";
+
+function opennamu_do_id_check(data) {
+    if(data.match(/\.|\:/)) {
+        return 0;
+    } else {
+        return 1;
+    }
+}
+
+function opennamu_do_url_encode(data) {
+    return encodeURIComponent(data);
+}

+ 10 - 0
views/main_css/js/func/http_warning_text.js

@@ -0,0 +1,10 @@
+"use strict";
+
+function opennamu_do_warning_text() {
+    if(window.location.protocol !== 'https:') {
+        let http_warning_text = document.getElementById('opennamu_http_warning_text_lang').innerHTML;
+        
+        document.getElementById('opennamu_http_warning_text').innerHTML = http_warning_text;
+        document.getElementById('opennamu_http_warning_text').style.margin = "10px 0px 0px 0px";
+    }
+}

+ 10 - 0
views/main_css/js/func/ie_end_of_life.js

@@ -0,0 +1,10 @@
+function opennamu_do_ie_end_support() {
+    if(document.currentScript === undefined) {
+        window.location = 'microsoft-edge:' + window.location;
+        setTimeout(function() {
+            window.location = 'https://go.microsoft.com/fwlink/?linkid=2135547';
+        }, 1);
+    }
+}
+
+opennamu_do_ie_end_support();

+ 2 - 0
views/main_css/js/load_shortcut.js → views/main_css/js/func/shortcut.js

@@ -1,3 +1,5 @@
+"use strict";
+
 let shortcut_key_list = [];
 document.onkeyup = function(e) {
     delete shortcut_key_list[e.key];

+ 91 - 0
views/main_css/js/func/user_name_parser.js

@@ -0,0 +1,91 @@
+"use strict";
+
+function opennamu_do_user_document_check() {
+    let data_all = document.getElementsByClassName('opennamu_user_link');
+    for(let for_a = 0; for_a < data_all.length; for_a++) {
+        if(data_all && data_all[for_a]) {
+            if(data_all[for_a].getAttribute('complete') === '1') {
+                continue;
+            }
+        }
+        
+        let data = data_all[for_a].innerHTML;
+        
+        let xhr = new XMLHttpRequest();
+        xhr.open("POST", "/api/user_info/" + opennamu_do_url_encode(data));
+        xhr.send();
+        
+        document.getElementsByClassName('opennamu_user_link')[for_a].setAttribute('complete', '1');
+        xhr.onreadystatechange = function() {
+            if(this.readyState === 4 && this.status === 200) {
+                // start part
+                let xhr_data = JSON.parse(this.responseText);
+                
+                // user document part
+                if(xhr_data[data]['document'] === 0) {
+                    document.getElementsByClassName('opennamu_user_link')[for_a].id = "not_thing";
+                }
+                
+                // user auth part
+                let user_data = document.getElementsByClassName('opennamu_user_link')[for_a].innerHTML;
+                if(xhr_data[data]['auth'] === 0) {
+                    
+                } else if(xhr_data[data]['auth'] === 1) {
+                    
+                } else {
+                    user_data = '<b>' + user_data + '</b>';
+                }
+                
+                // user title part
+                user_data = xhr_data[data]['user_title'] + user_data;
+                
+                // end part
+                document.getElementsByClassName('opennamu_user_link')[for_a].innerHTML = user_data;
+            }
+        }
+    }
+}
+
+function opennamu_do_ip_parser() {
+    let data_all = document.getElementsByClassName('opennamu_ip_render');
+    let data_list = {};
+    for(let for_a = 0; for_a < data_all.length; for_a++) {
+        if(data_all && data_all[for_a]) {
+            if(data_all[for_a].getAttribute('complete') === '1') {
+                continue;
+            }
+        }
+        
+        let data = data_all[for_a].innerHTML;
+        let data_raw = data;
+        
+        if(data_list[data_raw]) {
+            document.getElementsByClassName('opennamu_ip_render')[for_a].innerHTML = data_list[data_raw];
+            document.getElementsByClassName('opennamu_ip_render')[for_a].setAttribute('complete', '1');
+            
+            continue;
+        }
+        
+        if(opennamu_do_id_check(data_raw)) {
+            data = '' + 
+                '<a class="opennamu_user_link" ' + 
+                    'href="/w/user:' + opennamu_do_url_encode(data_raw) + '">' + 
+                    data_raw + 
+                '</a>' +
+            '';
+        } else {
+            
+        }
+        
+        data += ' <a href="/user/' + opennamu_do_url_encode(data_raw) + '">(🛠︎)</a>';
+
+        document.getElementsByClassName('opennamu_ip_render')[for_a].innerHTML = data;
+        document.getElementsByClassName('opennamu_ip_render')[for_a].setAttribute('complete', '1');
+
+        data_list[data_raw] = data;
+    }
+    
+    opennamu_do_user_document_check();
+}
+
+document.addEventListener("DOMContentLoaded", opennamu_do_ip_parser);

+ 3 - 1
views/main_css/js/load_skin_set.js

@@ -488,4 +488,6 @@ function main_css_skin_set() {
     ';
  
     simple_render('main_skin_set');
-}
+}
+
+document.addEventListener("DOMContentLoaded", main_css_skin_load);

+ 2 - 12
views/main_css/js/load_something.js

@@ -7,6 +7,7 @@ function load_user_info(name) {
     xhr.onreadystatechange = function() {
         if(this.readyState === 4 && this.status === 200) {
             document.getElementById('get_user_info').innerHTML += JSON.parse(this.responseText)['data'];
+            opennamu_do_ip_parser();
         }
     }
 }
@@ -148,15 +149,4 @@ function simple_render(name_ele) {
     }
     
     document.getElementById(name_ele).innerHTML = skin_set_data;
-}
-
-function ie_end_support() {
-    if(document.currentScript === undefined) {
-        window.location = 'microsoft-edge:' + window.location;
-        setTimeout(function() {
-            window.location = 'https://go.microsoft.com/fwlink/?linkid=2135547';
-        }, 1);
-    }
-}
-
-ie_end_support();
+}

+ 0 - 0
views/main_css/js/render/html.js


+ 520 - 0
views/main_css/js/render/markdown.js

@@ -0,0 +1,520 @@
+"use strict";
+
+class opennamu_render_markdown {
+    // Init Part
+    constructor(
+        render_part_id,
+        render_part_id_after,
+        render_part_id_add,
+        doc_name
+    ) {
+        this.doc_data = document.getElementById(render_part_id_add + render_part_id).innerHTML;
+
+        render_part_id_add = render_part_id_add.replace(/_/g, '<underBar>');
+
+        this.doc_data = this.doc_data.replace(/&amp;/g, '&');
+        this.doc_data = '<brStart>\n' + this.doc_data + '\n<brEnd>';
+        this.doc_data.replace(/\r/g, '');
+
+        this.doc_name = doc_name;
+            
+        this.parser_data_temp = {};
+        this.parser_data_temp_other = {};
+        this.parser_data_temp_other['toc'] = '';
+        this.parser_data_temp_other['footnote'] = '';
+        this.parser_data_temp_other['category'] = '';
+
+        this.parser_data_js = [];
+        
+        this.parser_count = {};
+        this.parser_count['parser'] = 0;
+        this.parser_count['nowiki'] = 0;
+        
+        this.render_part_id_add = render_part_id_add;
+        this.render_part_id_after = render_part_id_after;
+    }
+    
+    // Func Part
+    do_func_parser_to_text(data, parser_type = 'parser') {
+        let parser_data_temp = this.parser_data_temp;
+        let parser_match;
+        if(parser_type === 'nowiki') {
+            parser_match = /<(\/?nowiki[0-9]+Span)>/;
+        } else {
+            parser_match = /<(\/?render[0-9]+Span)>/;
+        }
+        
+        while(data.match(parser_match)) {
+            data = data.replace(parser_match, function(match, x1) {
+                return parser_data_temp[x1];
+            });
+        }
+        
+        return data;
+    }
+    
+    do_func_xss_encode(data) {
+        data = data.replace(/"/g, '&quot;');
+        data = data.replace(/</g, '&lt;');
+        data = data.replace(/</g, '&gt;');
+        
+        return data;
+    }
+    
+    do_func_xss_decode(data) {
+        data = data.replace(/&#x27;/g, '\'');
+        data = data.replace(/&quot;/g, '"');
+        data = data.replace(/&lt;/g, '<');
+        data = data.replace(/&gt;/g, '<');
+        
+        return data;
+    }
+    
+    // Render Part
+    do_part_text() {
+        let parser_count = this.parser_count['parser'];
+        let parser_data_temp = this.parser_data_temp;
+        
+        this.doc_data = this.doc_data.replace(/~~((?:(?!~~).)+)~~/g, function(match, x1) {
+            parser_count += 1;
+            let parser_count_str = String(parser_count);
+            
+            parser_data_temp['render' + parser_count_str + 'Span'] = '<s>';
+            parser_data_temp['/render' + parser_count_str + 'Span'] = '</s>';
+            
+            return '<render' + parser_count_str + 'Span>' + x1 + '</render' + parser_count_str + 'Span>';
+        });
+        
+        this.doc_data = this.doc_data.replace(/\*\*((?:(?!\*\*).)+)\*\*/g, function(match, x1) {
+            parser_count += 1;
+            let parser_count_str = String(parser_count);
+            
+            parser_data_temp['render' + parser_count_str + 'Span'] = '<b>';
+            parser_data_temp['/render' + parser_count_str + 'Span'] = '</b>';
+            
+            return '<render' + parser_count_str + 'Span>' + x1 + '</render' + parser_count_str + 'Span>';
+        });
+        
+        this.doc_data = this.doc_data.replace(/__((?:(?!__).)+)__/g, function(match, x1) {
+            parser_count += 1;
+            let parser_count_str = String(parser_count);
+            
+            parser_data_temp['render' + parser_count_str + 'Span'] = '<b>';
+            parser_data_temp['/render' + parser_count_str + 'Span'] = '</b>';
+            
+            return '<render' + parser_count_str + 'Span>' + x1 + '</render' + parser_count_str + 'Span>';
+        });
+        
+        this.doc_data = this.doc_data.replace(/\*([^*]+)\*/g, function(match, x1) {
+            parser_count += 1;
+            let parser_count_str = String(parser_count);
+            
+            parser_data_temp['render' + parser_count_str + 'Span'] = '<i>';
+            parser_data_temp['/render' + parser_count_str + 'Span'] = '</i>';
+            
+            return '<render' + parser_count_str + 'Span>' + x1 + '</render' + parser_count_str + 'Span>';
+        });
+        
+        this.doc_data = this.doc_data.replace(/_([^_]+)_/g, function(match, x1) {
+            parser_count += 1;
+            let parser_count_str = String(parser_count);
+            
+            parser_data_temp['render' + parser_count_str + 'Span'] = '<i>';
+            parser_data_temp['/render' + parser_count_str + 'Span'] = '</i>';
+            
+            return '<render' + parser_count_str + 'Span>' + x1 + '</render' + parser_count_str + 'Span>';
+        });
+        
+        this.doc_data = this.doc_data.replace(/&lt;ins&gt;((?:(?!&lt;ins&gt;|&lt;\/ins&gt;).)+)&lt;\/ins&gt;/g, function(match, x1) {
+            parser_count += 1;
+            let parser_count_str = String(parser_count);
+            
+            parser_data_temp['render' + parser_count_str + 'Span'] = '<u>';
+            parser_data_temp['/render' + parser_count_str + 'Span'] = '</u>';
+            
+            return '<render' + parser_count_str + 'Span>' + x1 + '</render' + parser_count_str + 'Span>';
+        });
+        
+        this.doc_data = this.doc_data.replace(/&lt;sub&gt;((?:(?!&lt;sub&gt;|&lt;\/sub&gt;).)+)&lt;\/sub&gt;/g, function(match, x1) {
+            parser_count += 1;
+            let parser_count_str = String(parser_count);
+            
+            parser_data_temp['render' + parser_count_str + 'Span'] = '<sub>';
+            parser_data_temp['/render' + parser_count_str + 'Span'] = '</sub>';
+            
+            return '<render' + parser_count_str + 'Span>' + x1 + '</render' + parser_count_str + 'Span>';
+        });
+        
+        this.doc_data = this.doc_data.replace(/&lt;sup&gt;((?:(?!&lt;sup&gt;|&lt;\/sup&gt;).)+)&lt;\/sup&gt;/g, function(match, x1) {
+            parser_count += 1;
+            let parser_count_str = String(parser_count);
+            
+            parser_data_temp['render' + parser_count_str + 'Span'] = '<sup>';
+            parser_data_temp['/render' + parser_count_str + 'Span'] = '</sup>';
+            
+            return '<render' + parser_count_str + 'Span>' + x1 + '</render' + parser_count_str + 'Span>';
+        });
+        
+        this.parser_count['parser'] = parser_count;
+        this.parser_data_temp = parser_data_temp;
+    }
+    
+    do_part_heading() {
+        let parser_count = this.parser_count['parser'];
+        let parser_data_temp = this.parser_data_temp;
+        
+        let toc_data = '';
+        
+        let heading_n = 0;
+        let heading_list = [0, 0, 0, 0, 0, 0];
+        let heading_regex = /\n(#{1,6})([^\n]+)\n/;
+        while(this.doc_data.match(heading_regex)) {
+            this.doc_data = this.doc_data.replace(heading_regex, function(match, x1, x2) {
+                let heading_level = x1.length - 1;
+                let heading_level_str = String(heading_level + 1);
+
+                heading_list[heading_level] += 1;
+                for(let for_a = heading_level + 1; for_a < 6; for_a++) {
+                    heading_list[for_a] = 0;
+                }
+
+                let heading_list_str = '';
+                for(let for_a = 0; for_a < 6; for_a++) {
+                    if(heading_list[for_a] !== 0) {
+                        heading_list_str += String(heading_list[for_a]) + '.'
+                    }
+                }
+                
+                let heading_list_str_2 = heading_list_str.replace(/\.$/, '');
+                
+                heading_n += 1;
+                let heading_n_str = String(heading_n);
+                
+                toc_data += '' +
+                    '<a href="#opennamuHeading' + heading_list_str_2 + '">' + heading_list_str + '</a> ' +
+                    '<span id="opennamuTOCcontent' + heading_n_str + '"></span>' +
+                    '<br>' +
+                ''
+                
+                let heading_data = x2;
+                heading_data = heading_data.replace(/^ /, '');
+
+                return '' + 
+                    '\n<brEnd>' + 
+                    '<h' + heading_level_str + ' id="opennamuHeading' + heading_list_str_2 + '">' + 
+                        '<a href="#opennamuTOC">' + heading_list_str + '</a> ' + 
+                        '<span id="opennamuHeadingContent' + heading_n_str + '">' + heading_data + '</span>' + 
+                    '</h' + heading_level_str + '>' +
+                    '<brStart>\n' +
+                '';
+            });
+        }
+        
+        this.parser_data_temp_other['toc'] = toc_data;
+    }
+    
+    do_part_image() {
+        let render_main = this;
+        let render_part_id_add = this.render_part_id_add;
+        
+        let parser_count = this.parser_count['parser'];
+        let parser_data_temp = this.parser_data_temp;
+        
+        this.doc_data = this.doc_data.replace(/!\[([^\[\]]*)\]\(([^\(\)]*)\)/g, function(match, x1, x2) {
+            if(x1 === '' && x2 === '') {
+                return '<imageBlink>';
+            } else {
+                if(x2 !== '' && x2.match(/^https?:\/\//)) {
+                    parser_count += 1;
+                    let parser_count_str = String(parser_count);
+                    
+                    let image_src = render_main.do_func_xss_encode(x2);
+                    let image_alt;
+                    if(x1 !== '') {
+                        image_alt = render_main.do_func_xss_encode(x1);
+                    } else {
+                        image_alt = image_src;
+                    }
+                    
+                    parser_data_temp['render' + parser_count_str + 'Span'] = '<img alt="' + image_alt + '" src="' + image_src + '">';
+                    parser_data_temp['/render' + parser_count_str + 'Span'] = '';
+
+                    return '<render' + parser_count_str + 'Span></render' + parser_count_str + 'Span>';
+                } else {
+                    parser_count += 1;
+                    let parser_count_str = String(parser_count);
+
+                    parser_data_temp['render' + parser_count_str + 'Span'] = '<img>';
+                    parser_data_temp['/render' + parser_count_str + 'Span'] = '';
+
+                    return '<render' + parser_count_str + 'Span></render' + parser_count_str + 'Span>';
+                }
+            }
+        });
+        
+        this.doc_data = this.doc_data.replace(/<imageBlink>/g, '![]()');
+        
+        this.parser_count['parser'] = parser_count;
+        this.parser_data_temp = parser_data_temp;
+    }
+    
+    do_part_link() {
+        let render_main = this;
+        let render_part_id_add = this.render_part_id_add;
+        
+        let parser_count = this.parser_count['parser'];
+        let parser_data_temp = this.parser_data_temp;
+        
+        this.doc_data = this.doc_data.replace(/\[([^\[\]]*)\]\(([^\(\)]*)\)/g, function(match, x1, x2) {
+            if(x1 === '' && x2 === '') {
+                return '<linkBlink>';
+            } else {
+                if(x2 !== '' && x2.match(/^https?:\/\//)) {
+                    parser_count += 1;
+                    let parser_count_str = String(parser_count);
+                    
+                    let link_main = render_main.do_func_xss_encode(x2);;
+                    let link_sub;
+                    if(x1 === '') {
+                        link_sub = x2;
+                    } else {
+                        link_sub = x1;
+                    }
+                    
+                    parser_data_temp['render' + parser_count_str + 'Span'] = '<a href="' + link_main + '">';
+                    parser_data_temp['/render' + parser_count_str + 'Span'] = '</a>';
+
+                    return '<render' + parser_count_str + 'Span>' + link_sub + '</render' + parser_count_str + 'Span>';
+                } else {
+                    parser_count += 1;
+                    let parser_count_str = String(parser_count);
+
+                    let link_main;
+                    let link_sub;
+                    let link_title;
+                    if(x2 === '') {
+                        link_main = x1;
+                        link_sub = x1;
+                    } else if(x1 === '') {
+                        link_main = x2;
+                        link_sub = x2;
+                    } else {
+                        link_main = x2;
+                        link_sub = x1;
+                    }
+                    
+                    link_title = render_main.do_func_xss_encode(link_main);
+
+                    link_main = render_main.do_func_xss_decode(link_main);
+                    link_main = opennamu_do_url_encode(link_main);
+
+                    parser_data_temp['render' + parser_count_str + 'Span'] = '<a class="' + render_part_id_add + 'opennamuLink" title="' + link_title + '" href="/w/' + link_main + '">';
+                    parser_data_temp['/render' + parser_count_str + 'Span'] = '</a>';
+
+                    return '<render' + parser_count_str + 'Span>' + link_sub + '</render' + parser_count_str + 'Span>';
+                }
+            }
+        });
+        
+        this.doc_data = this.doc_data.replace(/<linkBlink>/g, '[]()');
+        
+        this.parser_count['parser'] = parser_count;
+        this.parser_data_temp = parser_data_temp;
+    }
+    
+    do_part_footnote_list() {
+        if(this.parser_data_temp_other['footnote'] !== '') {
+            let footnote = '';
+            footnote += '<ul id="footnote<underBar>data">';
+            footnote += this.parser_data_temp_other['footnote'];
+            footnote += '</ul>';
+            
+            this.parser_data_temp_other['footnote'] = '';
+            
+            return footnote;
+        } else {
+            return '';
+        }
+    }
+    
+    do_part_footnote() {
+        let render_main = this;
+        
+        let parser_count = this.parser_count['parser'];
+        let parser_data_temp = this.parser_data_temp;
+        let parser_data_temp_other = this.parser_data_temp_other;
+        
+        let footnote_n = 0;
+        let footnote_name_all = {};
+        this.doc_data = this.doc_data.replace(/(?:\[\^((?:(?!\[\^| ).)*)(?: ((?:(?!\[\^|\]).)+))?\]|(\[fnote\(\)]))/g, function(match, x1, x2, x3) {
+            if(x3 === undefined) {
+                if(x1 === '' && x2 === undefined) {
+                    return '<footnoteBlink>';
+                } else {
+                    footnote_n += 1;
+
+                    let footnote_name;
+                    let footnote_id = String(footnote_n);
+                    if(x1 === '') {
+                        footnote_name = footnote_id;
+                    } else {
+                        footnote_name = x1;
+                    }
+                    
+                    let footnote_content;
+                    if(x2 === undefined) {
+                        if(footnote_name_all[footnote_name]) {
+                            footnote_content = footnote_name_all[footnote_name];
+                        } else {
+                            footnote_content = '';
+                            footnote_name_all[footnote_name] = footnote_content;
+                        }
+                    } else {
+                        footnote_content = x2;
+                        footnote_name_all[footnote_name] = footnote_content;
+                    }
+                    
+                    let footnote_list = '';
+                    footnote_list += '<li>';
+                    footnote_list += '<a id="opennamuFnGo' + footnote_id + '" href="#opennamuFnIn' + footnote_id + '">'
+                    footnote_list += '(' + footnote_name + ')';
+                    footnote_list += '</a>';
+                    footnote_list += ' ';
+                    footnote_list += footnote_content;
+                    footnote_list += '</li>';
+                    
+                    parser_data_temp_other['footnote'] += footnote_list;
+
+                    parser_count += 1;
+                    let parser_count_str = String(parser_count);
+                    
+                    let footnote_data = '';
+                    footnote_data += '<sup>'
+                    footnote_data += '<a id="opennamuFnIn' + footnote_id + '" href="#opennamuFnGo' + footnote_id + '">';
+                    footnote_data += '(' + footnote_name + ')';
+                    footnote_data += '</a>';
+                    footnote_data += '</sup>';
+
+                    parser_data_temp['render' + parser_count_str + 'Span'] = footnote_data;
+                    parser_data_temp['/render' + parser_count_str + 'Span'] = '';
+
+                    return '<render' + parser_count_str + 'Span></render' + parser_count_str + 'Span>';
+                }
+            } else {
+                return render_main.do_part_footnote_list();
+            }
+        });
+        
+        this.doc_data = this.doc_data.replace(/<footnoteBlink>/g, '[^]');
+        this.doc_data += this.do_part_footnote_list();
+        
+        this.parser_count['parser'] = parser_count;
+        this.parser_data_temp = parser_data_temp;
+        this.parser_data_temp_other = parser_data_temp_other;
+    }
+    
+    do_part_macro() {
+        let render_main = this;
+        let render_part_id_add = this.render_part_id_add;
+        
+        let parser_count = this.parser_count['parser'];
+        let parser_data_temp = this.parser_data_temp;
+        let parser_data_temp_other = this.parser_data_temp_other;
+        
+        this.doc_data = this.doc_data.replace(/\[([^\[\(<>]+)\(((?:(?!\(|\)\]|<|>).)*)\)\]/g, function(match, x1, x2) {
+            if(x1 === 'anchor') {
+                parser_count += 1;
+                let parser_count_str = String(parser_count);
+                
+                let anchor_data = render_main.do_func_parser_to_text(x2, 'nowiki');
+                anchor_data = render_main.do_func_xss_encode(anchor_data);
+
+                parser_data_temp['render' + parser_count_str + 'Span'] = '<span id="' + anchor_data + '">';
+                parser_data_temp['/render' + parser_count_str + 'Span'] = '</span>';
+
+                return '<render' + parser_count_str + 'Span></render' + parser_count_str + 'Span>' 
+            } else if(x1 === 'category') {
+                let category = x2.split(',');
+
+                let category_data = render_main.do_func_parser_to_text(category[0], 'nowiki');
+                
+                let link_main = 'category:' + category_data;
+                let link_title = render_main.do_func_xss_encode(link_main);
+                
+                link_main = render_main.do_func_xss_decode(link_main);
+                link_main = opennamu_do_url_encode(link_main);
+                
+                parser_data_temp_other['category'] += '<a class="' + render_part_id_add + 'opennamuLink" title="' + link_title + '" href="/w/' + link_main + '">';
+                parser_data_temp_other['category'] += category_data;
+                parser_data_temp_other['category'] += '</a>';
+                parser_data_temp_other['category'] += ' | ';
+                
+                return '';
+            } else if(x1 === 'toc') {
+                if(parser_data_temp_other['toc'] !== '') {
+                    return '' +
+                        '<div class="opennamuTOC">' + 
+                            '<span class="opennamuTOCtitle">' +
+                                'TOC' +
+                            '</span>' + 
+                            '<br>' + 
+                            '<br>' + 
+                            parser_data_temp_other['toc'] + 
+                        '</div>' +
+                    '';
+                } else {
+                    return '';
+                }
+            }
+            else {
+                return '';
+            }
+        });
+        
+        this.parser_count['parser'] = parser_count;
+        this.parser_data_temp = parser_data_temp;
+        this.parser_data_temp_other = parser_data_temp_other;
+    }
+    
+    do_part_final() {
+        this.doc_data = this.doc_data.replace(/<brStart>\n?/g, '');
+        this.doc_data = this.doc_data.replace(/\n?<brEnd>/g, '');
+        
+        this.doc_data = this.doc_data.replace(/<underBar>/g, '_');
+        this.render_part_id_add = this.render_part_id_add.replace(/<underBar>/g, '_');
+        
+        this.doc_data = this.doc_data.replace(/\n/g, '<br>');
+        
+        if(this.parser_data_temp_other['category'] !== '') {
+            let category = this.parser_data_temp_other['category'];
+            category = category.replace(/ \| $/, '');
+            
+            this.doc_data += '<hr class="main_hr">';
+            this.doc_data += '<div id="cate_all"><div id="cate">';
+            this.doc_data += 'Category : ';
+            this.doc_data += category;
+            this.doc_data += '</div></div>';
+        }
+    }
+    
+    // Main Part
+    do_main() {
+        this.do_part_heading();
+        this.do_part_footnote();
+        this.do_part_macro();
+        this.do_part_image();
+        this.do_part_link();
+        this.do_part_text();
+        this.do_part_final();
+        
+        this.doc_data = this.do_func_parser_to_text(this.doc_data);
+        document.getElementById(this.render_part_id_add + this.render_part_id_after).innerHTML = this.doc_data;
+        for(let x1 in this.parser_data_js) {
+            eval(this.parser_data_js[x1]);
+        }
+        
+        new opennamu_render_wiki(
+            render_part_id_add = this.render_part_id_add
+        ).do_main();
+    }
+}

+ 15 - 0
views/main_css/js/render/onmark.js

@@ -0,0 +1,15 @@
+"use strict";
+
+class opennamu_render_onmark {
+    constructor(
+        doc_data,
+        doc_name
+    ) {
+        this.doc_data = doc_data;
+        this.doc_name = doc_name;
+    }
+    
+    text_part() {
+        return doc_data;
+    }
+}

+ 86 - 0
views/main_css/js/render/wiki.js

@@ -0,0 +1,86 @@
+"use strict";
+
+class opennamu_render_wiki {
+    constructor(
+        render_part_id_add
+    ) {
+        this.render_part_id_add = render_part_id_add;
+    }
+    
+    do_part_image() {
+        
+    }
+    
+    do_part_link() {
+        let render_part_id_add = this.render_part_id_add;
+        
+        let link_list = {};
+        let link_list_sub = [];
+        for(
+            let for_a = 0;
+            document.getElementsByClassName(this.render_part_id_add + 'opennamuLink')[for_a];
+            for_a++
+        ) {
+            let link_data = document.getElementsByClassName(this.render_part_id_add + 'opennamuLink')[for_a];
+            
+            link_list_sub.push(link_data.title);
+            
+            if(!link_list[link_data.title]) {
+                link_list[link_data.title] = [for_a];
+            } else {
+                link_list[link_data.title].push(for_a);
+            }
+        }
+        
+        let data_form = new FormData();
+        data_form.append('title_list', JSON.stringify(link_list_sub));
+        
+        let xhr = new XMLHttpRequest();
+        xhr.open("POST", "/api/w/test/doc_tool/exist");
+        xhr.send(data_form);
+        xhr.onreadystatechange = function() {
+            if(this.readyState === 4 && this.status === 200) {
+                let xhr_data = JSON.parse(this.responseText);
+                for(let for_a in link_list) {
+                    if(!xhr_data[for_a]) {
+                        for(var for_b in link_list[for_a]) {
+                            document.getElementsByClassName(render_part_id_add + 'opennamuLink')[link_list[for_a][for_b]].id = "not_thing";
+                        }
+                    }
+                }
+            }
+        }
+    }
+    
+    do_part_toc() {
+        for(
+            let for_a = 1;
+            document.getElementById('opennamuHeadingContent' + String(for_a));
+            for_a++
+        ) {
+            let heading_data = document.getElementById('opennamuHeadingContent' + String(for_a));
+            document.getElementById('opennamuTOCcontent' + String(for_a)).innerHTML = heading_data.innerText;
+            
+            document.getElementById('opennamuHeadingContent' + String(for_a)).id = heading_data.innerText;
+        }
+        
+        let toc_data_all = document.getElementsByClassName('opennamuTOC');
+        let toc_data = '';
+        for(
+            let for_a = 0;
+            for_a < toc_data_all.length;
+            for_a++
+        ) {
+            if(toc_data === '') {
+                toc_data = toc_data_all[0].innerHTML;
+            }
+            
+            document.getElementsByClassName('opennamuTOC')[for_a].innerHTML = toc_data;
+        }
+    }
+    
+    do_main() {
+        this.do_part_link();
+        this.do_part_toc();
+    }
+}

+ 0 - 9
views/main_css/js/render_markdown.js

@@ -1,9 +0,0 @@
-function do_markdown_render(
-    test_mode = 'test', 
-    name_id = '', 
-    name_include = '', 
-    name_doc = '', 
-    doc_data = ''
-) {
-    
-}

+ 37 - 14
views/main_css/js/render_onmark.js

@@ -112,10 +112,20 @@ function do_xss_change(data) {
     data = data.replace(/&lt;/g, '<');
     data = data.replace(/&gt;/g, '>');
     data = data.replace(/&amp;/g, '&');
+    data = data.replace(/&quot;/g, '"');
     
     return data;
 }
 
+function do_html_escape(data) {
+    data = data.replace(/</g, '&lt;');
+    data = data.replace(/>/g, '&gt;');
+    data = data.replace(/&/g, '&amp;');
+    data = data.replace(/"/g, '&quot;');
+    
+    return data
+}
+
 function do_end_br_replace(data) {
     data = data.replace(/(\n| )+$/, '\n');
     
@@ -140,6 +150,14 @@ function do_onmark_text_render(data) {
     return data;
 }
 
+function do_onmark_set_toc_name(toc_name) {
+    let toc_data = document.getElementById("heading_text_" + toc_name).innerText;
+    
+    for(let for_a = 0; document.getElementsByClassName("toc_text_" + toc_name)[for_a]; for_a++) {
+        document.getElementsByClassName("toc_text_" + toc_name)[for_a].innerHTML = toc_data;
+    }
+}
+
 function do_onmark_heading_render(
     data, 
     data_js, 
@@ -192,13 +210,13 @@ function do_onmark_heading_render(
         toc_data += '' +
             '<span style="margin-left: ' + String((heading_level_string.match(/\./g).length - 1) * 10) + 'px;">' +
                 '<a href="#s-' + heading_level_string_no_end + '">' + 
-                    heading_level_string + ' ' +
+                    heading_level_string + 
                 '</a> ' + 
-                '<span id="toc_text_' + heading_level_string_no_end + '"></span>' +
+                '<span class="toc_text_' + heading_level_string_no_end + '"></span>' +
             '</span>' +
             '\n' +
         ''
-        data_js += 'document.getElementById("toc_text_' + heading_level_string_no_end + '").innerHTML = document.getElementById("heading_text_' + heading_level_string_no_end + '").innerText;\n';
+        data_js += 'do_onmark_set_toc_name("' + heading_level_string_no_end + '");\n';
         
         data = data.replace(heading_re, 
             '\n' +
@@ -274,12 +292,12 @@ function do_onmark_link_render(data, data_js, name_doc, name_include, data_nowik
                     file_name = file_type.slice(0, file_type.length - 1).join('.');
                     file_type = file_type[file_type.length - 1];
 
-                    var file_src = do_url_change(file_name) + '.' + file_type;       
-                    var file_alt = file_name + '.' + file_type;
+                    var file_src = do_url_change(do_xss_change(file_name)) + '.' + do_html_escape(file_type);
+                    var file_alt = do_html_escape(file_name + '.' + file_type);
                     var file_exist = 1;
                 } else {
-                    var file_src = file_name;
-                    var file_alt = file_name;
+                    var file_src = do_html_escape(file_name);
+                    var file_alt = do_html_escape(file_name);
                     var file_exist = 0;
                 }
 
@@ -319,7 +337,7 @@ function do_onmark_link_render(data, data_js, name_doc, name_include, data_nowik
                                 'under_style="' + file_style + '" ' +
                                 'under_alt="' + file_alt + '" ' +
                                 'under_src="' + file_src + '" ' +
-                                'under_href="' + (file_exist === 0 ? "out_link" : '/upload?name=' + do_url_change(file_name)) + '">' +
+                                'under_href="' + (file_exist === 0 ? "out_link" : '/upload?name=' + file_src.replace(/\.[^.]+$/, '')) + '">' +
                         '</span>' + 
                     '</span>' +
                 ''
@@ -559,7 +577,7 @@ function do_onmark_footnote_render(data, name_include) {
 function do_onmark_macro_render(data, data_js) {
     data = data.replace(/\[([^[\](]+)\(((?:(?!\)\]).)+)\)\]/g, function(x, x_1, x_2) {
         x_1 = x_1.toLowerCase();
-        if(x_1 === 'youtube' || x_1 === 'kakaotv' || x_1 === 'nicovideo' || x_1 === 'navertv') {
+        if(x_1 === 'youtube' || x_1 === 'kakaotv' || x_1 === 'nicovideo' || x_1 === 'navertv' || x_1 === 'vimeo') {
             var video_code = x_2.match(/^([^,]+)/);
             video_code = video_code ? video_code[1] : '';
             
@@ -584,9 +602,11 @@ function do_onmark_macro_render(data, data_js) {
                 var video_src = 'https://tv.kakao.com/embed/player/cliplink/' + video_code +'?service=kakao_tv'
             } else if(x_1 === 'nicovideo') {
                 var video_src = 'https://embed.nicovideo.jp/watch/' + video_code
-            } else {
+            } else if(x_1 === 'navertv') {
                 var video_src = 'https://tv.naver.com/embed/' + video_code
-            }
+            } else {
+		var video_src = 'https://player.vimeo.com/video/' + video_code
+	    }
             
             return '<iframe style="width: ' + video_width + '; height: ' + video_height + ';" src="' + video_src + '" frameborder="0" allowfullscreen></iframe>';
         } else if(x_1 === 'anchor') {
@@ -613,7 +633,7 @@ function do_onmark_macro_render(data, data_js) {
             
             var date_end = Math.floor((date_now - date_old) / (24 * 60 * 60 * 1000));
             
-            return date_end > 0 ? '+' + date_end : '-' + date_end;
+            return (date_end > 0 ? '+' : '') + date_end;
         } else if(x_1 === 'age') {
             var date_old = new Date(x_2);
             var date_now = new Date(do_return_date());
@@ -631,7 +651,7 @@ function do_onmark_macro_render(data, data_js) {
     var pagecount_n = 0;
     data = data.replace(/\[([^[*()\]]+)\]/g, function(x, x_1) {
         x_1 = x_1.toLowerCase();
-        if(x_1 === 'date') {
+        if(x_1 === 'date' || x_1 === 'datetime') {
             return do_return_date();
         } else if(x_1 === 'clearfix') {
             return '<div style="clear:both"></div>';
@@ -1319,6 +1339,9 @@ function do_onmark_render(
     var data_js = '';
     var data_backlink = [];
     var data_nowiki = {};
+        
+    name_doc = do_xss_change(name_doc);
+    console.log(name_doc);
 
     let xhr = new XMLHttpRequest();
     xhr.open("GET", "/api/setting/inter_wiki");
@@ -1457,4 +1480,4 @@ function do_onmark_render(
             }
         }
     }
-}
+}

+ 13 - 9
views/main_css/js/render_wiki.js

@@ -8,7 +8,6 @@ function get_link_state(data) {
     var link_list_2 = {}
     for(var i = 0; document.getElementsByClassName(data + 'link_finder')[i]; i++) {
         var data_class = document.getElementsByClassName(data + 'link_finder')[i];
-        console.log(data_class.href)
         if(
             data_class.id !== 'out_link' && 
             data_class.id !== 'inside' && 
@@ -60,12 +59,19 @@ function get_heading_name() {
     }
 }
 
-function load_image_link(data) {
-    data.innerHTML = '' +
+function load_image_link(data, data_type = 0) {
+    let data_end = '';
+    data_end = '' +
         '<img   style="' + data.getAttribute('under_style') + '" ' + 
                 'alt="' + data.getAttribute('under_alt') + '" ' + 
                 'src="' + data.getAttribute('under_src') + '">' +
     '';
+    
+    if(data_type === 0) {
+        data.innerHTML = data_end;
+    } else {
+        return data_end;
+    }
 }
 
 function get_file_state_extermal(data, data_exter) {
@@ -99,9 +105,7 @@ function get_file_state_extermal(data, data_exter) {
             '';
         } else {
             document.getElementsByClassName(data + 'file_finder')[key].innerHTML = '' +
-                '<img   style="' + data_class[key].getAttribute('under_style') + '" ' + 
-                        'alt="' + data_class[key].getAttribute('under_alt') + '" ' + 
-                        'src="' + data_class[key].getAttribute('under_src') + '">' +
+                load_image_link(data_class[key], 1) +
             '';
         }
     }
@@ -198,7 +202,7 @@ function get_file_state_intermal(data, data_inter) {
                                             'under_style="' + data_class[key_4].getAttribute('under_style') + '" ' +
                                             'under_alt="' + data_class[key_4].getAttribute('under_alt') + '" ' +
                                             'under_src="/image/' + data_dict[key_3]['file_sha224'] + '.' + data_dict[key_3]['file_type'] + '">' + 
-                                            '(' + data_class[key_4].getAttribute('under_alt') + ' load)' +
+                                            '(' + data_class[key_4].getAttribute('under_alt') + ' GET)' +
                                         '</a>' +
                                     '';
                                 }
@@ -206,10 +210,10 @@ function get_file_state_intermal(data, data_inter) {
                                 for(var key_4 in data_dict[key_3]['list']) {
                                     var key_4 = data_dict[key_3]['list'][key_4];
                                     document.getElementsByClassName(data + 'file_finder')[key_4].innerHTML = '' +
-                                        '<img   style="' + data_class[key_4].getAttribute('under_style') + '" ' + 
+                                        '<img   style="' + data_class[key_4].getAttribute('under_style') + ';cursor: pointer;" ' + 
+                                                'onclick="window.location.href=\'/w/file:' + data_class[key_4].getAttribute('under_src') + '\';"' +
                                                 'alt="' + data_class[key_4].getAttribute('under_alt') + '" ' + 
                                                 'src="/image/' + data_dict[key_3]['file_sha224'] + '.' + data_dict[key_3]['file_type'] + '">' +
-                                        '' +
                                     '';
                                 }
                             }

+ 5 - 0
views/main_css/js/route/edit.js

@@ -0,0 +1,5 @@
+"use strict";
+
+function opennamu_route_edit() {
+    
+}

+ 9 - 0
views/main_css/js/route/main_skin_set.js

@@ -0,0 +1,9 @@
+"use strict";
+
+function opennamu_do_main_skin_set() {
+
+}
+
+function opennamu_route_main_skin_set() {
+    
+}

+ 40 - 25
views/main_css/js/load_topic.js → views/main_css/js/route/thread.js

@@ -1,27 +1,37 @@
-function new_topic_load(topic_num, type_do = 'top', some = '', where = 'top_topic') {
+// 좀 더 개선 필요
+// use strict 적용 필요 (eval 동작에 문제 있음)
+function opennamu_do_thread_make(topic_num, type_do = 'top', some = '', where = 'top_topic') {
+    let url = '';
     if(type_do === 'top') {
-        var url = "/api/thread/" + topic_num + "/top";
+        url = "/api/thread/" + topic_num + "/top";
     } else if(type_do === 'main') {
-        var url = "/api/thread/" + topic_num;
+        url = "/api/thread/" + topic_num;
     } else {
-        var url = "/api/thread/" + topic_num + some;
+        url = "/api/thread/" + topic_num + some;
     }
 
-    var xhr = new XMLHttpRequest();
+    let xhr = new XMLHttpRequest();
     xhr.open("GET", url, true);
     xhr.send(null);
 
     xhr.onreadystatechange = function() {
         if(this.readyState === 4 && this.status === 200) {
-            var data_t = JSON.parse(this.responseText);
-            var start = 0;
-            var key_v = '/normal/1';
+            let data_t = JSON.parse(this.responseText);
             
-            for(var key in data_t) {
-                var data_a = '';
+            let start = 0;
+            let key_v = '/normal/1';
+            let admin = '';
+            let ip_first = '';
+            
+            let data_all = '';
+            let data_all_js = '';
+            
+            for(let key in data_t) {
+                let data_a = '';
+                
                 if(start === 0) {
-                    var admin = data_t['data_main']['admin'];
-                    var ip_first = data_t['data_main']['ip_first'];
+                    admin = data_t['data_main']['admin'];
+                    ip_first = data_t['data_main']['ip_first'];
                 
                     start = 1;
                 }
@@ -32,13 +42,13 @@ function new_topic_load(topic_num, type_do = 'top', some = '', where = 'top_topi
                 
                 key_v = '/normal/' + String(Number(key) + 1);
                 
-                var color_b = '';
-                var color_t = '';
+                let color_b = '';
+                let color_t = '';
                 
-                var ip = data_t[key]['ip_pas'];
-                var ip_o = data_t[key]['ip'];
-                var blind = data_t[key]['blind'];
-                var data_i_pas = data_t[key]['data_pas'][0];
+                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];
                 
                 if(data_i_pas === '') {
                     data_i_pas = '<br>';
@@ -99,27 +109,32 @@ function new_topic_load(topic_num, type_do = 'top', some = '', where = 'top_topi
                     '<hr class="main_hr">' + 
                 ''
 
-                document.getElementById(where).innerHTML += data_a;
-                eval(data_t[key]['data_pas'][1]);
+                data_all += data_a;
+                data_all_js += data_t[key]['data_pas'][1] + '\n';
             }
             
+            document.getElementById(where).innerHTML += data_all;
+            eval(data_all_js);
+            
+            opennamu_do_ip_parser();
+            
             if(type_do === 'top') {
-                new_topic_load(topic_num, 'main', '', 'main_topic');
+                opennamu_do_thread_make(topic_num, 'main', '', 'main_topic');
             } else if(type_do === 'main') {
-                data_url_v = window.location.href.split('#');
+                let data_url_v = window.location.href.split('#');
                 if(data_url_v.length !== 0) {
                     if(document.getElementById(data_url_v[1])) {
                         document.getElementById(data_url_v[1]).focus();
                     }
                 }
                 
-                new_topic_load(topic_num, 're', key_v, where);
+                opennamu_do_thread_make(topic_num, 're', key_v, where);
             } else if(type_do === 're') {
                 setTimeout(function() {
                     if(start === 0) {
-                        new_topic_load(topic_num, 're', some, where);
+                        opennamu_do_thread_make(topic_num, 're', some, where);
                     } else {
-                        new_topic_load(topic_num, 're', key_v, where);
+                        opennamu_do_thread_make(topic_num, 're', key_v, where);
                     }
                 }, 2000);
             }