Procházet zdrojové kódy

Merge pull request #1857 from openNAMU/beta

임시로 stable 버전 올리기
잉여개발기 (SPDV) před 2 roky
rodič
revize
c03ab28ac9
74 změnil soubory, kde provedl 1749 přidání a 1173 odebrání
  1. 1 1
      .github/PULL_REQUEST_TEMPLATE.md
  2. 59 74
      app.py
  3. 8 1
      emergency_tool.py
  4. 27 0
      lang/en-US.json
  5. 29 4
      lang/ko-KR.json
  6. 1 2
      readme-en.md
  7. 1 2
      readme.md
  8. 2 0
      requirements.txt
  9. 5 3
      route/__init__.py
  10. 29 0
      route/api_bbs_w_comment.py
  11. 26 0
      route/api_bbs_w_post.py
  12. 2 1
      route/api_skin_info.py
  13. 110 15
      route/api_topic.py
  14. 1 2
      route/api_w.py
  15. 7 1
      route/bbs_main.py
  16. 2 2
      route/bbs_make.py
  17. 11 11
      route/bbs_w.py
  18. 51 58
      route/bbs_w_edit.py
  19. 184 195
      route/bbs_w_post.py
  20. 24 26
      route/bbs_w_set.py
  21. 91 54
      route/edit.py
  22. 10 12
      route/edit_delete_file.py
  23. 1 0
      route/edit_delete_multiple.py
  24. 1 1
      route/give_admin_groups.py
  25. 1 1
      route/give_delete_admin_group.py
  26. 3 4
      route/list_image_file.py
  27. 8 5
      route/list_long_page.py
  28. 2 0
      route/list_old_page.py
  29. 40 27
      route/list_user_check.py
  30. 5 15
      route/list_user_check_delete.py
  31. 19 5
      route/login_login.py
  32. 1 1
      route/login_register_submit.py
  33. 2 23
      route/main_func_easter_egg.py
  34. 1 0
      route/main_setting.py
  35. 8 5
      route/main_setting_main.py
  36. 5 1
      route/main_setting_phrase.py
  37. 5 0
      route/main_setting_skin_set.py
  38. 3 0
      route/main_sys_update.py
  39. 7 4
      route/main_tool_redirect.py
  40. 1 1
      route/recent_block.py
  41. 1 2
      route/recent_history_add.py
  42. 468 481
      route/tool/func.py
  43. 37 9
      route/tool/func_render.py
  44. 230 39
      route/tool/func_render_namumark.py
  45. 1 0
      route/tool/func_tool.py
  46. 21 57
      route/topic.py
  47. 1 0
      route/topic_list.py
  48. 1 1
      route/user_info.py
  49. 1 3
      route/user_setting.py
  50. 9 0
      route/user_setting_skin_set_main.py
  51. 4 5
      route/view_acl.py
  52. 4 4
      route/view_diff.py
  53. 1 1
      route/view_read.py
  54. 1 1
      route/vote_add.py
  55. 2 2
      route/vote_select.py
  56. binární
      route_go/bin/main_easter_egg.amd64.bin
  57. binární
      route_go/bin/main_easter_egg.amd64.exe
  58. binární
      route_go/bin/main_easter_egg.arm64.bin
  59. binární
      route_go/bin/main_easter_egg.arm64.exe
  60. 22 0
      route_go/linux_amd64.sh
  61. 37 0
      route_go/main_easter_egg.go
  62. 1 1
      version.json
  63. 4 0
      views/main_css/css/main.css
  64. 5 5
      views/main_css/css/sub/dark.css
  65. 3 0
      views/main_css/js/func/check_new_thread.ts
  66. 5 1
      views/main_css/js/func/func.js
  67. 15 0
      views/main_css/js/route/bbs_w_post.js
  68. 14 0
      views/main_css/js/route/bbs_w_post.ts
  69. 52 1
      views/main_css/js/route/editor.js
  70. 8 0
      views/ringo/css/main.css
  71. 1 1
      views/ringo/index.html
  72. 4 0
      views/tenshi/css/main.css
  73. 1 1
      views/tenshi/index.html
  74. 1 1
      views/tenshi/info.json

+ 1 - 1
.github/PULL_REQUEST_TEMPLATE.md

@@ -1,4 +1,4 @@
 <!--
 <!--
-stable, beta branch로 요청을 보내지 마십시오. 개발은 dev branch에서 이루어집니다.
+stable, beta branch로 요청을 보내지 말아주세요. 개발은 dev branch에서 이루어집니다.
 Don't request merge your commit to stable, beta branch, please request to dev branch.
 Don't request merge your commit to stable, beta branch, please request to dev branch.
 -->
 -->

+ 59 - 74
app.py

@@ -1,10 +1,16 @@
 # Init
 # Init
 import os
 import os
 import re
 import re
+import logging
+import shutil
 
 
 from route.tool.func import *
 from route.tool.func import *
 from route import *
 from route import *
 
 
+if platform.system() == 'Linux':
+    for for_a in os.listdir(os.path.join("route_go", "bin")):
+        os.system('chmod +x ./route_go/bin/' + for_a)
+
 # Init-Version
 # Init-Version
 with open('version.json', encoding = 'utf8') as file_data:
 with open('version.json', encoding = 'utf8') as file_data:
     version_list = json.loads(file_data.read())
     version_list = json.loads(file_data.read())
@@ -293,52 +299,40 @@ app.route('/extension_filter/del/<everything:name>', defaults = { 'tool' : 'del_
 app.route('/extension_filter/add', methods = ['POST', 'GET'], defaults = { 'tool' : 'plus_extension_filter' })(filter_inter_wiki_add)
 app.route('/extension_filter/add', methods = ['POST', 'GET'], defaults = { 'tool' : 'plus_extension_filter' })(filter_inter_wiki_add)
 
 
 # Func-list
 # Func-list
-# /list/document/old
 app.route('/list/document/old')(list_old_page)
 app.route('/list/document/old')(list_old_page)
 app.route('/list/document/old/<int:num>')(list_old_page)
 app.route('/list/document/old/<int:num>')(list_old_page)
 
 
-# /list/document/acl
 app.route('/list/document/acl')(list_acl)
 app.route('/list/document/acl')(list_acl)
 app.route('/list/document/acl/<int:arg_num>')(list_acl)
 app.route('/list/document/acl/<int:arg_num>')(list_acl)
 
 
-# /list/document/need
 app.route('/list/document/need')(list_please)
 app.route('/list/document/need')(list_please)
 app.route('/list/document/need/<int:arg_num>')(list_please)
 app.route('/list/document/need/<int:arg_num>')(list_please)
 
 
-# /list/document/all
 app.route('/list/document/all')(list_title_index)
 app.route('/list/document/all')(list_title_index)
 app.route('/list/document/all/<int:num>')(list_title_index)
 app.route('/list/document/all/<int:num>')(list_title_index)
 
 
-# /list/document/long
 app.route('/list/document/long')(list_long_page)
 app.route('/list/document/long')(list_long_page)
+app.route('/list/document/long/<int:arg_num>')(list_long_page)
 
 
-# /list/document/short
 app.route('/list/document/short', defaults = { 'tool' : 'short_page' })(list_long_page)
 app.route('/list/document/short', defaults = { 'tool' : 'short_page' })(list_long_page)
+app.route('/list/document/short/<int:arg_num>', defaults = { 'tool' : 'short_page' })(list_long_page)
 
 
-# /list/file
 app.route('/list/file')(list_image_file)
 app.route('/list/file')(list_image_file)
+app.route('/list/file/<int:arg_num>')(list_image_file)
 
 
-# /list/admin
-# /list/admin/list
 app.route('/list/admin')(list_admin)
 app.route('/list/admin')(list_admin)
 
 
-# /list/admin/auth_use
 app.route('/list/admin/auth_use', methods = ['POST', 'GET'])(list_admin_auth_use)
 app.route('/list/admin/auth_use', methods = ['POST', 'GET'])(list_admin_auth_use)
 app.route('/list/admin/auth_use/<arg_search>/<int:arg_num>', methods = ['POST', 'GET'])(list_admin_auth_use)
 app.route('/list/admin/auth_use/<arg_search>/<int:arg_num>', methods = ['POST', 'GET'])(list_admin_auth_use)
 
 
-# /list/user
 app.route('/list/user')(list_user)
 app.route('/list/user')(list_user)
 app.route('/list/user/<int:arg_num>')(list_user)
 app.route('/list/user/<int:arg_num>')(list_user)
 
 
-# /list/user/check
-@app.route('/check/<name>')
-def give_user_check(name = None):
-    return give_user_check_2(name)
-    
-# /list/user/check/delete
-@app.route('/check_delete', methods = ['POST', 'GET'])
-def give_user_check_delete():
-    return give_user_check_delete_2()
+app.route('/list/user/check/<name>')(list_user_check)
+app.route('/list/user/check/<name>/<do_type>')(list_user_check)
+app.route('/list/user/check/<name>/<do_type>/<int:arg_num>')(list_user_check)
+app.route('/list/user/check/<name>/<do_type>/<int:arg_num>/<plus_name>')(list_user_check)
+app.route('/list/user/check/delete/<name>/<ip>/<time>/<do_type>', methods = ['POST', 'GET'])(list_user_check_delete)
 
 
 # Func-auth
 # Func-auth
 # /auth/give
 # /auth/give
@@ -354,33 +348,23 @@ app.route('/auth/give/ban_regex/<everything:name>', methods = ['POST', 'GET'], d
 app.route('/auth/give/ban_multiple', methods = ['POST', 'GET'], defaults = { 'ban_type' : 'multiple' })(give_user_ban)
 app.route('/auth/give/ban_multiple', methods = ['POST', 'GET'], defaults = { 'ban_type' : 'multiple' })(give_user_ban)
 
 
 # /auth/list
 # /auth/list
-@app.route('/admin_group')
-def list_admin_group():
-    return list_admin_group_2()
+app.route('/admin_group')(list_admin_group_2)
 
 
 # /auth/list/add/<name>
 # /auth/list/add/<name>
-@app.route('/admin_plus/<name>', methods = ['POST', 'GET'])
-def give_admin_groups(name = None):
-    return give_admin_groups_2(name)
+app.route('/admin_plus/<name>', methods = ['POST', 'GET'])(give_admin_groups_2)
 
 
 # /auth/list/delete/<name>
 # /auth/list/delete/<name>
-@app.route('/delete_admin_group/<name>', methods = ['POST', 'GET'])
-def give_delete_admin_group(name = None):
-    return give_delete_admin_group_2(name)
+app.route('/delete_admin_group/<name>', methods = ['POST', 'GET'])(give_delete_admin_group_2)
 
 
 app.route('/auth/give/fix/<user_name>', methods = ['POST', 'GET'])(give_user_fix)
 app.route('/auth/give/fix/<user_name>', methods = ['POST', 'GET'])(give_user_fix)
 
 
-@app.route('/app_submit', methods = ['POST', 'GET'])
-def recent_app_submit():
-    return recent_app_submit_2()
+app.route('/app_submit', methods = ['POST', 'GET'])(recent_app_submit_2)
 
 
 # /auth/history
 # /auth/history
 # ongoing 반영 필요
 # ongoing 반영 필요
-@app.route('/block_log')
-@app.route('/block_log/<regex("user"):tool>/<name>')
-@app.route('/block_log/<regex("admin"):tool>/<name>')
-def recent_block(name = 'Test', tool = 'all'):
-    return recent_block_2(name, tool)
+app.route('/block_log')(recent_block_2)
+app.route('/block_log/<regex("user"):tool>/<name>')(recent_block_2)
+app.route('/block_log/<regex("admin"):tool>/<name>')(recent_block_2)
 
 
 # Func-history
 # Func-history
 app.route('/recent_change')(recent_change)
 app.route('/recent_change')(recent_change)
@@ -495,15 +479,9 @@ app.route('/star_doc', defaults = { 'tool' : 'star_doc' })(user_watch_list)
 app.route('/star_doc/<everything:name>', defaults = { 'tool' : 'star_doc' })(user_watch_list_name)
 app.route('/star_doc/<everything:name>', defaults = { 'tool' : 'star_doc' })(user_watch_list_name)
 
 
 # 개편 보류중 S
 # 개편 보류중 S
-@app.route('/change/email', methods = ['POST', 'GET'])
-def user_setting_email():
-    return user_setting_email_2()
-
+app.route('/change/email', methods = ['POST', 'GET'])(user_setting_email_2)
 app.route('/change/email/delete')(user_setting_email_delete)
 app.route('/change/email/delete')(user_setting_email_delete)
-
-@app.route('/change/email/check', methods = ['POST', 'GET'])
-def user_setting_email_check():
-    return user_setting_email_check_2()
+app.route('/change/email/check', methods = ['POST', 'GET'])(user_setting_email_check_2)
 # 개편 보류중 E
 # 개편 보류중 E
 
 
 # Func-login
 # Func-login
@@ -513,29 +491,12 @@ def user_setting_email_check():
 # register -> register/email -> regiter/email/check with reg_id
 # register -> register/email -> regiter/email/check with reg_id
 # pass_find -> pass_find/email with find_id
 # pass_find -> pass_find/email with find_id
 
 
-@app.route('/login', methods = ['POST', 'GET'])
-def login_login():
-    return login_login_2()
-
-@app.route('/login/2fa', methods = ['POST', 'GET'])
-def login_login_2fa():
-    return login_login_2fa_2()
-
-@app.route('/register', methods = ['POST', 'GET'])
-def login_register():
-    return login_register_2()
-
-@app.route('/register/email', methods = ['POST', 'GET'])
-def login_register_email():
-    return login_register_email_2()
-
-@app.route('/register/email/check', methods = ['POST', 'GET'])
-def login_register_email_check():
-    return login_register_email_check_2()
-
-@app.route('/register/submit', methods = ['POST', 'GET'])
-def login_register_submit():
-    return login_register_submit_2()
+app.route('/login', methods = ['POST', 'GET'])(login_login_2)
+app.route('/login/2fa', methods = ['POST', 'GET'])(login_login_2fa_2)
+app.route('/register', methods = ['POST', 'GET'])(login_register_2)
+app.route('/register/email', methods = ['POST', 'GET'])(login_register_email_2)
+app.route('/register/email/check', methods = ['POST', 'GET'])(login_register_email_check_2)
+app.route('/register/submit', methods = ['POST', 'GET'])(login_register_submit_2)
 
 
 app.route('/login/find')(login_find)
 app.route('/login/find')(login_find)
 app.route('/login/find/key', methods = ['POST', 'GET'])(login_find_key)
 app.route('/login/find/key', methods = ['POST', 'GET'])(login_find_key)
@@ -560,11 +521,11 @@ app.route('/bbs/make', methods = ['POST', 'GET'])(bbs_make)
 # app.route('/bbs/main/set')
 # app.route('/bbs/main/set')
 app.route('/bbs/w/<int:bbs_num>')(bbs_w)
 app.route('/bbs/w/<int:bbs_num>')(bbs_w)
 app.route('/bbs/set/<int:bbs_num>', methods = ['POST', 'GET'])(bbs_w_set)
 app.route('/bbs/set/<int:bbs_num>', methods = ['POST', 'GET'])(bbs_w_set)
-app.route('/bbs/edit/<int:bbs_num>', methods = ['POST', 'GET'])(bbs_edit)
-app.route('/bbs/edit/preview/<int:bbs_num>', methods = ['POST', 'GET'], defaults = { 'do_type' : 'preview' })(bbs_edit)
+app.route('/bbs/edit/<int:bbs_num>', methods = ['POST', 'GET'])(bbs_w_edit)
+app.route('/bbs/edit/preview/<int:bbs_num>', methods = ['POST', 'GET'], defaults = { 'do_type' : 'preview' })(bbs_w_edit)
 app.route('/bbs/w/<int:bbs_num>/<int:post_num>', methods = ['POST', 'GET'])(bbs_w_post)
 app.route('/bbs/w/<int:bbs_num>/<int:post_num>', methods = ['POST', 'GET'])(bbs_w_post)
-app.route('/bbs/edit/<int:bbs_num>/<int:post_num>', methods = ['POST', 'GET'])(bbs_edit)
-app.route('/bbs/edit/preview/<int:bbs_num>/<int:post_num>', methods = ['POST', 'GET'], defaults = { 'do_type' : 'preview' })(bbs_edit)
+app.route('/bbs/edit/<int:bbs_num>/<int:post_num>', methods = ['POST', 'GET'])(bbs_w_edit)
+app.route('/bbs/edit/preview/<int:bbs_num>/<int:post_num>', methods = ['POST', 'GET'], defaults = { 'do_type' : 'preview' })(bbs_w_edit)
 app.route('/bbs/w/preview/<int:bbs_num>/<int:post_num>', methods = ['POST'], defaults = { 'do_type' : 'preview' })(bbs_w_post)
 app.route('/bbs/w/preview/<int:bbs_num>/<int:post_num>', methods = ['POST'], defaults = { 'do_type' : 'preview' })(bbs_w_post)
 # app.route('/bbs/edit/<int:bbs_num>/<int:post_num>')
 # app.route('/bbs/edit/<int:bbs_num>/<int:post_num>')
 
 
@@ -574,6 +535,9 @@ app.route('/api/w/<everything:name>/doc_tool/<tool>', methods = ['POST', 'GET'])
 app.route('/api/w/<everything:name>', methods = ['GET', 'POST'])(api_w)
 app.route('/api/w/<everything:name>', methods = ['GET', 'POST'])(api_w)
 app.route('/api/raw/<everything:name>')(api_raw)
 app.route('/api/raw/<everything:name>')(api_raw)
 
 
+app.route('/api/bbs/w/<sub_code>')(api_bbs_w_post)
+app.route('/api/bbs/w/comment/<sub_code>')(api_bbs_w_comment)
+
 app.route('/api/version', defaults = { 'version_list' : version_list })(api_version)
 app.route('/api/version', defaults = { 'version_list' : version_list })(api_version)
 app.route('/api/skin_info')(api_skin_info)
 app.route('/api/skin_info')(api_skin_info)
 app.route('/api/skin_info/<name>')(api_skin_info)
 app.route('/api/skin_info/<name>')(api_skin_info)
@@ -638,6 +602,28 @@ app.route('/setting/skin_set', methods = ['POST', 'GET'])(main_setting_skin_set)
 
 
 app.route('/easter_egg')(main_func_easter_egg)
 app.route('/easter_egg')(main_func_easter_egg)
 
 
+def main_easter_egg_go():
+    with get_db_connect() as conn:
+        print(platform.machine())
+        if platform.system() == 'Linux':
+            if platform.machine() in ["AMD64", "x86_64"]:
+                data = os.popen(os.path.join(".", "route_go", "bin", "main_easter_egg.amd64.bin")).read()
+            else:
+                data = os.popen(os.path.join(".", "route_go", "bin", "main_easter_egg.arm64.bin")).read()
+        else:
+            if platform.machine() in ["AMD64", "x86_64"]:
+                data = os.popen(os.path.join(".", "route_go", "bin", "main_easter_egg.amd64.exe")).read()
+            else:
+                data = os.popen(os.path.join(".", "route_go", "bin", "main_easter_egg.arm64.exe")).read()
+
+        return easy_minify(flask.render_template(skin_check(),
+            imp = ['Easter Egg', wiki_set(), wiki_custom(), wiki_css([0, 0])],
+            data = data,
+            menu = 0
+        ))
+
+app.route('/easter_egg_go')(main_easter_egg_go)
+
 # views -> view
 # views -> view
 app.route('/view/<path:name>')(main_view)
 app.route('/view/<path:name>')(main_view)
 app.route('/views/<path:name>')(main_view)
 app.route('/views/<path:name>')(main_view)
@@ -656,6 +642,5 @@ if __name__ == "__main__":
         app,
         app,
         host = server_set['host'],
         host = server_set['host'],
         port = int(server_set['port']),
         port = int(server_set['port']),
-        threads = 1,
         clear_untrusted_proxy_headers = True
         clear_untrusted_proxy_headers = True
-    )
+    )

+ 8 - 1
emergency_tool.py

@@ -4,6 +4,7 @@ import os
 import platform
 import platform
 import urllib
 import urllib
 import zipfile
 import zipfile
+import urllib.request
 
 
 from route.tool.func import *
 from route.tool.func import *
 
 
@@ -25,7 +26,7 @@ if data_db_load == 'Y':
     curs = conn.cursor()
     curs = conn.cursor()
 else:
 else:
     print('----')
     print('----')
-    print('You can use [9, 11]')
+    print('You can use [9, 11, 19]')
 
 
 # Main
 # Main
 print('----')
 print('----')
@@ -49,6 +50,8 @@ print('18. Change wiki access password')
 print('19. Forced update')
 print('19. Forced update')
 print('20. Change domain')
 print('20. Change domain')
 print('21. Change TLS')
 print('21. Change TLS')
+print('22. Delete body top')
+print('23. Delete body bottom')
 
 
 print('----')
 print('----')
 what_i_do = input('Select : ')
 what_i_do = input('Select : ')
@@ -249,6 +252,10 @@ elif what_i_do == '21':
 
 
     curs.execute(db_change('delete from other where name = "http_select"'))
     curs.execute(db_change('delete from other where name = "http_select"'))
     curs.execute(db_change('insert into other (name, data, coverage) values ("http_select", ?, "")'), [tls_v])
     curs.execute(db_change('insert into other (name, data, coverage) values ("http_select", ?, "")'), [tls_v])
+elif what_i_do == '22':
+    curs.execute(db_change('delete from other where name = "body"'))
+elif what_i_do == '23':
+    curs.execute(db_change('delete from other where name = "bottom_body"'))
 else:
 else:
     raise ValueError(what_i_do)
     raise ValueError(what_i_do)
 
 

+ 27 - 0
lang/en-US.json

@@ -240,6 +240,25 @@
         "user_added_menu" : "User added menu",
         "user_added_menu" : "User added menu",
         "move_redirect_make" : "Redirect document generation (Only if possible)",
         "move_redirect_make" : "Redirect document generation (Only if possible)",
         "user_fix" : "Fix user",
         "user_fix" : "Fix user",
+        "sub_user_name" : "Sub user name",
+        "_comment_" : "BBS",
+            "bbs" : "BBS",
+            "bbs_main" : "BBS main",
+            "bbs_name" : "BBS name",
+            "bbs_make" : "Create BBS",
+            "order" : "Order",
+            "comment_base" : "Comment based",
+            "thread_base" : "Thread based",
+            "bbs_set" : "BBS set",
+            "comment" : "Comment",
+            "reply" : "Reply",
+            "post_edit" : "Modify post",
+            "post_add" : "Add post",
+            "_comment_" : "BBS ACL",
+                "bbs_view_acl" : "BBS ACL to view posts",
+                "bbs_acl" : "BBS ACL",
+                "bbs_edit_acl" : "BBS ACL to write post",
+                "bbs_comment_acl" : "BBS ACL to write comment",
         "_comment_" : "Edit",
         "_comment_" : "Edit",
             "load" : "Load another document",
             "load" : "Load another document",
             "turn_off_monaco" : "Turn off monaco editor",
             "turn_off_monaco" : "Turn off monaco editor",
@@ -263,6 +282,10 @@
                 "font_size" : "Font size",
                 "font_size" : "Font size",
                 "image_paste" : "Paste Image by Ctrl + C and V",
                 "image_paste" : "Paste Image by Ctrl + C and V",
                 "monaco_editor" : "Monaco editor",
                 "monaco_editor" : "Monaco editor",
+                "footnote_render" : "Footnote rendering",
+                "footnote_number" : "Footnote number output",
+                "only_number" : "Only number",
+                "footnote_real_num_view" : "Footnote original number view",
             "_comment_" : "Option",
             "_comment_" : "Option",
                 "change_to_normal" : "Change to plain text.",
                 "change_to_normal" : "Change to plain text.",
                 "change_to_link" : "Change to Link.",
                 "change_to_link" : "Change to Link.",
@@ -318,6 +341,7 @@
                 "server_set" : "Server-related settings",
                 "server_set" : "Server-related settings",
                 "edit_set" : "Edit-related settings",
                 "edit_set" : "Edit-related settings",
                 "communication_set" : "Communication-related settings",
                 "communication_set" : "Communication-related settings",
+                "render_set" : "Rendering-related settings",
     
     
                 "namumark_fully_compatible_mode" : "namumark design compatible mode",
                 "namumark_fully_compatible_mode" : "namumark design compatible mode",
                 "wiki_name" : "Wikis name",
                 "wiki_name" : "Wikis name",
@@ -352,6 +376,8 @@
                 "set_wiki_access_password_need" : "Password required for wiki access",
                 "set_wiki_access_password_need" : "Password required for wiki access",
                 "set_wiki_access_password" : "Wiki access password",
                 "set_wiki_access_password" : "Wiki access password",
                 "set_history_recording_off" : "Stop recording history",
                 "set_history_recording_off" : "Stop recording history",
+                "link_case_insensitive" : "Link case insensitive",
+                "hide_user_name" : "Hide member name",
             "_comment_" : "Text",
             "_comment_" : "Text",
                 "register_text" : "Terms of sign-up",
                 "register_text" : "Terms of sign-up",
                 "non_login_alert" : "Non-login alert",
                 "non_login_alert" : "Non-login alert",
@@ -557,6 +583,7 @@
             "error_title_length_too_long" : "Documents title or Discussion topic length is too long. Maximum number of characters : ",
             "error_title_length_too_long" : "Documents title or Discussion topic length is too long. Maximum number of characters : ",
             "error_password_length_too_short" : "Password length is too short. Minimum number of characters : ",
             "error_password_length_too_short" : "Password length is too short. Minimum number of characters : ",
             "error_password_require_for_wiki_access" : "A password is required to access the wiki.",
             "error_password_require_for_wiki_access" : "A password is required to access the wiki.",
+            "timeout_error" : "Running is taking too long. Maximum running time (Second(s)) : ",
         "_comment_3.2_" : "Warning",
         "_comment_3.2_" : "Warning",
             "http_warning" : "Warning: If you are not on HTTPS connection, your information can be leaked. The users themselves have responsibility to any problems that happen because of this.",
             "http_warning" : "Warning: If you are not on HTTPS connection, your information can be leaked. The users themselves have responsibility to any problems that happen because of this.",
             "user_head_warning" : "User data will be deleted if you close the browser or when you sign in.",
             "user_head_warning" : "User data will be deleted if you close the browser or when you sign in.",

+ 29 - 4
lang/ko-KR.json

@@ -84,7 +84,7 @@
     "file_name_error": "파일명에는 알파벳, 한글, 공백, 밑줄 및 빼기 기호만 사용할 수 있습니다.",
     "file_name_error": "파일명에는 알파벳, 한글, 공백, 밑줄 및 빼기 기호만 사용할 수 있습니다.",
     "pass": "넘기기",
     "pass": "넘기기",
     "recaptcha_error": "'로봇이 아닙니다'를 통해 reCAPTCHA를 통과하세요.",
     "recaptcha_error": "'로봇이 아닙니다'를 통해 reCAPTCHA를 통과하세요.",
-    "file_capacity_error": "최대 파일 크기 (MB): ",
+    "file_capacity_error": "최대 파일 크기 (MB) : ",
     "setting": "설정",
     "setting": "설정",
     "end": "끝",
     "end": "끝",
     "error": "오류",
     "error": "오류",
@@ -307,7 +307,7 @@
     "requires_approval": "가입시 승인 필요",
     "requires_approval": "가입시 승인 필요",
     "approval_question": "회원가입 질문",
     "approval_question": "회원가입 질문",
     "public_key": "공개 키",
     "public_key": "공개 키",
-    "fast_edit_error": "편집 속도가 너무 빠릅니다. 제한 (초): ",
+    "fast_edit_error": "편집 속도가 너무 빠릅니다. 제한 (초) : ",
     "main_acl_setting": "기본 ACL 설정",
     "main_acl_setting": "기본 ACL 설정",
     "edit_req_acl": "편집 요청 ACL",
     "edit_req_acl": "편집 요청 ACL",
     "application_list": "가입신청 목록",
     "application_list": "가입신청 목록",
@@ -528,6 +528,31 @@
     "spread": "펼침",
     "spread": "펼침",
     "popup": "팝업",
     "popup": "팝업",
     "popover": "팝오버",
     "popover": "팝오버",
-    "user_fix" : "사용자 수정",
-    "2fa_off" : "2FA 끄기"
+    "user_fix": "사용자 수정",
+    "2fa_off": "2FA 끄기",
+    "bbs": "게시판",
+    "bbs_main": "게시판 메인",
+    "bbs_name": "게시판 이름",
+    "bbs_make": "게시판 생성",
+    "order": "순번",
+    "comment_base": "댓글 기반",
+    "thread_base": "스레드 기반",
+    "bbs_set": "게시판 설정",
+    "bbs_view_acl": "게시판 읽기 ACL",
+    "bbs_acl": "게시판 ACL",
+    "bbs_edit_acl": "게시판 글 작성 ACL",
+    "bbs_comment_acl": "게시판 댓글 작성 ACL",
+    "sub_user_name": "보조 사용자 이름",
+    "render_set": "렌더링 관련 설정",
+    "link_case_insensitive": "링크 대소문자 구분 안함",
+    "hide_user_name": "가입자 이름 숨기기",
+    "comment": "댓글",
+    "reply": "대댓글",
+    "timeout_error": "실행 시간이 너무 오래 걸립니다. 최대 실행 시간 (초) : ",
+    "footnote_render": "각주 렌더링",
+    "footnote_number": "각주 번호 출력",
+    "only_number": "숫자만",
+    "footnote_real_num_view": "각주 실제 번호 보기",
+    "post_edit" : "게시글 수정",
+    "post_add" : "게시글 추가"
 }
 }

+ 1 - 2
readme-en.md

@@ -1,8 +1,7 @@
 [(en-US)](./readme-en.md) | [(ko-KR)](./readme.md)
 [(en-US)](./readme-en.md) | [(ko-KR)](./readme.md)
 
 
 # openNAMU
 # openNAMU
-[![Up to Python 3.7](https://img.shields.io/badge/python->=%203.7-blue.svg)](https://python.org)
-[![Up to PyPy 3.7](https://img.shields.io/badge/pypy3-%3E=%203.7-blue.svg)](https://www.pypy.org/)
+[![Up to Python 3.8](https://img.shields.io/badge/python->=%203.8-blue.svg)](https://python.org)
 [![LICENSE](https://img.shields.io/badge/license-BSD%203--Clause-lightgrey.svg)](./LICENSE)
 [![LICENSE](https://img.shields.io/badge/license-BSD%203--Clause-lightgrey.svg)](./LICENSE)
 
 
 ![](https://raw.githubusercontent.com/openNAMU/openNAMU/beta/.github/logo.png)
 ![](https://raw.githubusercontent.com/openNAMU/openNAMU/beta/.github/logo.png)

+ 1 - 2
readme.md

@@ -1,8 +1,7 @@
 [(en-US)](./readme-en.md) | [(ko-KR)](./readme.md)
 [(en-US)](./readme-en.md) | [(ko-KR)](./readme.md)
 
 
 # 오픈나무
 # 오픈나무
-[![Python 3.7 이상](https://img.shields.io/badge/python->=%203.7-blue.svg)](https://python.org)
-[![PyPy 3.7 이상](https://img.shields.io/badge/pypy3-%3E=%203.7-blue.svg)](https://www.pypy.org/)
+[![Python 3.8 이상](https://img.shields.io/badge/python->=%203.8-blue.svg)](https://python.org)
 [![라이선스](https://img.shields.io/badge/license-BSD%203--Clause-lightgrey.svg)](./LICENSE)
 [![라이선스](https://img.shields.io/badge/license-BSD%203--Clause-lightgrey.svg)](./LICENSE)
 
 
 ![](https://raw.githubusercontent.com/openNAMU/openNAMU/beta/.github/logo.png)
 ![](https://raw.githubusercontent.com/openNAMU/openNAMU/beta/.github/logo.png)

+ 2 - 0
requirements.txt

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

+ 5 - 3
route/__init__.py

@@ -12,8 +12,10 @@ from route.api_topic import api_topic
 from route.api_user_info import api_user_info
 from route.api_user_info import api_user_info
 from route.api_version import api_version
 from route.api_version import api_version
 from route.api_w import api_w
 from route.api_w import api_w
+from route.api_bbs_w_post import api_bbs_w_post
+from route.api_bbs_w_comment import api_bbs_w_comment
 
 
-from route.bbs_edit import bbs_edit
+from route.bbs_w_edit import bbs_w_edit
 from route.bbs_main import bbs_main
 from route.bbs_main import bbs_main
 from route.bbs_make import bbs_make
 from route.bbs_make import bbs_make
 from route.bbs_w import bbs_w
 from route.bbs_w import bbs_w
@@ -40,8 +42,6 @@ from route.give_admin_groups import give_admin_groups_2
 from route.give_auth import give_auth
 from route.give_auth import give_auth
 from route.give_delete_admin_group import give_delete_admin_group_2
 from route.give_delete_admin_group import give_delete_admin_group_2
 from route.give_user_ban import give_user_ban
 from route.give_user_ban import give_user_ban
-from route.give_user_check import give_user_check_2
-from route.give_user_check_delete import give_user_check_delete_2
 from route.give_user_fix import give_user_fix
 from route.give_user_fix import give_user_fix
 
 
 from route.list_acl import list_acl
 from route.list_acl import list_acl
@@ -54,6 +54,8 @@ from route.list_old_page import list_old_page
 from route.list_please import list_please
 from route.list_please import list_please
 from route.list_title_index import list_title_index
 from route.list_title_index import list_title_index
 from route.list_user import list_user
 from route.list_user import list_user
+from route.list_user_check import list_user_check
+from route.list_user_check_delete import list_user_check_delete
 
 
 from route.login_find import login_find
 from route.login_find import login_find
 from route.login_find_email import login_find_email
 from route.login_find_email import login_find_email

+ 29 - 0
route/api_bbs_w_comment.py

@@ -0,0 +1,29 @@
+from .tool.func import *
+
+def api_bbs_w_comment(sub_code = ''):
+    with get_db_connect() as conn:
+        curs = conn.cursor()
+
+        curs.execute(db_change('select set_name, set_data, set_code, set_id from bbs_data where (set_name = "comment" or set_name = "comment_date" or set_name = "comment_user_id") and set_id = ? order by set_code + 0 asc'), [sub_code])
+        db_data = curs.fetchall()
+        if not db_data:
+            return flask.jsonify({})
+        else:
+            temp_id = ''
+            temp_dict = {}
+            temp_list = []
+
+            for for_a in db_data:
+                if temp_id != for_a[2]:
+                    if temp_dict != {}:
+                        temp_list += [dict(temp_dict)]
+
+                    temp_id = for_a[2]
+                    temp_dict['code'] = for_a[2]
+
+                temp_dict[for_a[0]] = for_a[1]
+
+            if temp_dict != {}:
+                temp_list += [dict(temp_dict)]
+
+            return flask.jsonify(temp_list)

+ 26 - 0
route/api_bbs_w_post.py

@@ -0,0 +1,26 @@
+from .tool.func import *
+
+def api_bbs_w_post(sub_code = ''):
+    sub_code_split = sub_code.split('-')
+    if len(sub_code_split) < 2:
+        sub_code_split = ['', '']
+
+    with get_db_connect() as conn:
+        curs = conn.cursor()
+
+        curs.execute(db_change('select set_name, set_data, set_code from bbs_data where set_id = ? and set_code = ?'), [sub_code_split[0], sub_code_split[1]])
+        db_data = curs.fetchall()
+        if not db_data:
+            return flask.jsonify({})
+        else:
+            temp_id = ''
+            temp_dict = {}
+
+            for for_a in db_data:
+                if temp_id != for_a[2]:
+                    temp_id = for_a[2]
+                    temp_dict['code'] = for_a[2]
+
+                temp_dict[for_a[0]] = for_a[1]
+
+            return flask.jsonify(temp_dict)

+ 2 - 1
route/api_skin_info.py

@@ -1,3 +1,5 @@
+import urllib.request
+
 from .tool.func import *
 from .tool.func import *
 
 
 def api_skin_info(name = ''):
 def api_skin_info(name = ''):
@@ -59,7 +61,6 @@ def api_skin_info(name = ''):
                                     "skin_ver" : get_data["skin_ver"]
                                     "skin_ver" : get_data["skin_ver"]
                                 }}}
                                 }}}
 
 
-
                     a_data = {**a_data, **{ i : json_data }}
                     a_data = {**a_data, **{ i : json_data }}
 
 
             return flask.jsonify(a_data)
             return flask.jsonify(a_data)

+ 110 - 15
route/api_topic.py

@@ -1,5 +1,111 @@
 from .tool.func import *
 from .tool.func import *
-from .bbs_w_post import bbs_w_post_make_thread
+
+def api_topic_thread_make(user_id, date, data, code, color = '', blind = '', add_style = ''):
+    if blind != '':
+        if data == '':
+            color_b = 'opennamu_comment_blind'
+        else:
+            color_b = 'opennamu_comment_blind_admin'
+    else:
+        color_b = 'opennamu_comment_blind_not'
+
+    return '''
+        <table class="opennamu_comment" style="''' + add_style + '''">
+            <tr>
+                <td class="opennamu_comment_color_''' + color + '''">
+                    <a href="#thread_shortcut" id="''' + code + '''">#''' + code + '''</a>
+                    ''' + user_id + '''
+                    <span style="float: right;">''' + date + '''</span>
+                </td>
+            </tr>
+            <tr>
+                <td class="''' + color_b + '''" id="opennamu_comment_data_main">
+                    ''' + data + '''
+                </td>
+            </tr>
+        </table>
+    '''
+
+def api_topic_thread_pre_render(curs, data, num, ip, topic_num = '', name = '', sub = '', do_type = 'thread'):
+    # 이거 좀 엉성해서 언젠간 손 보고 싶음
+
+    call_thread_regex = r"( |\n|^)(?:#([0-9]+)(?:-([0-9]+))?)( |\n|$)"
+    call_thread_count = len(re.findall(call_thread_regex, data)) * 3
+    while 1:
+        rd_data = re.search(call_thread_regex, data)
+        if call_thread_count < 0:
+            break
+        elif not rd_data:
+            break
+        else:
+            rd_data = rd_data.groups()
+
+            view_data = rd_data[1]
+            send_topic_num = topic_num
+            if rd_data[2]:
+                view_data += '-' + rd_data[2]
+                if do_type == 'thread':
+                    send_topic_num = rd_data[2]
+                else:
+                    set_id = topic_num.split('-')
+
+                    send_topic_num = set_id[0] + '-' + rd_data[2]
+                    view_data += '-' + set_id[0]
+
+            if do_type == 'thread':
+                curs.execute(db_change("select ip from topic where code = ? and id = ?"), [send_topic_num, rd_data[1]])
+            else:
+                if rd_data[1] == '0':
+                    set_id = send_topic_num.split('-')
+                    set_id = ['', ''] if len(set_id) < 2 else set_id
+
+                    curs.execute(db_change('select set_data from bbs_data where set_name = "user_id" and set_id = ? and set_code = ?'), [set_id[0], set_id[1]])
+                else:
+                    curs.execute(db_change('select set_data from bbs_data where set_name = "comment_user_id" and set_id = ? and set_code = ?'), [send_topic_num, rd_data[1]])
+
+            ip_data = curs.fetchall()
+            if ip_data and ip_or_user(ip_data[0][0]) == 0:
+                if do_type == 'thread':
+                    add_alarm(ip_data[0][0], ip, '<a href="/thread/' + topic_num + '#' + num + '">' + html.escape(name) + ' - ' + html.escape(sub) + '#' + num + '</a>')
+                else:
+                    set_id = topic_num.split('-')
+                    set_id = ['', ''] if len(set_id) < 2 else set_id
+
+                    add_alarm(ip_data[0][0], ip, 'BBS <a href="/bbs/w/' + set_id[0] + '/' + set_id[1] + '#' + num + '">' + html.escape(name) + ' - ' + html.escape(sub) + '#' + num + '</a>')
+
+            data = re.sub(call_thread_regex, rd_data[0] + '<topic_a_' + do_type + '>#' + view_data + '</topic_a_' + do_type + '>' + rd_data[3], data, 1)
+
+        call_thread_count -= 1
+
+    call_user_regex = r"( |\n|^)(?:@([^ \n]+))( |\n|$)"
+    call_user_count = len(re.findall(call_user_regex, data)) * 3
+    while 1:
+        rd_data = re.search(call_user_regex, data)
+        if call_user_count < 0:
+            break
+        elif not rd_data:
+            break
+        else:
+            rd_data = rd_data.groups()
+
+            curs.execute(db_change("select ip from history where ip = ? limit 1"), [rd_data[1]])
+            ip_data = curs.fetchall()
+            if not ip_data:
+                curs.execute(db_change("select ip from topic where ip = ? limit 1"), [rd_data[1]])
+                ip_data = curs.fetchall()
+
+            if ip_data and ip_or_user(ip_data[0][0]) == 0:
+                if do_type == 'thread':
+                    add_alarm(ip_data[0][0], ip, '<a href="/thread/' + topic_num + '#' + num + '">' + html.escape(name) + ' - ' + html.escape(sub) + '#' + num + '</a>')
+                else:
+                    set_id = topic_num.split('-')
+                    add_alarm(ip_data[0][0], ip, 'BBS <a href="/bbs/w/' + set_id[0] + '/' + set_id[1] + '#' + num + '">' + html.escape(name) + ' - ' + html.escape(sub) + '#' + num + '</a>')
+
+            data = re.sub(call_user_regex, rd_data[0] + '<topic_call>@' + rd_data[1] + '</topic_call>' + rd_data[2], data, 1)
+
+        call_user_count -= 1
+
+    return data
 
 
 def api_topic(topic_num = 1, tool = 'normal', num = '', render = ''):
 def api_topic(topic_num = 1, tool = 'normal', num = '', render = ''):
     with get_db_connect() as conn:
     with get_db_connect() as conn:
@@ -45,19 +151,8 @@ def api_topic(topic_num = 1, tool = 'normal', num = '', render = ''):
                     if data_v != '':
                     if data_v != '':
                         data_v = render_set(
                         data_v = render_set(
                             doc_data = data_v, 
                             doc_data = data_v, 
-                            data_type = 'api_view',
-                            data_in = 'topic_' + topic_num + '_' + i[0],
-                            doc_acl = 0
-                        )
-                        data_v[0] = re.sub(
-                            r'&lt;topic_a&gt;(?P<in>(?:(?!&lt;\/topic_a&gt;).)+)&lt;\/topic_a&gt;',
-                            '<a href="\g<in>">\g<in></a>',
-                            data_v[0]
-                        )
-                        data_v[0] = re.sub(
-                            r'&lt;topic_call&gt;@(?P<in>(?:(?!&lt;\/topic_call&gt;).)+)&lt;\/topic_call&gt;',
-                            '<a href="/w/user:\g<in>">@\g<in></a>',
-                            data_v[0]
+                            data_type = 'api_thread',
+                            data_in = 'topic_' + topic_num + '_' + i[0]
                         )
                         )
                     else:
                     else:
                         data_v = ['', '']
                         data_v = ['', '']
@@ -88,7 +183,7 @@ def api_topic(topic_num = 1, tool = 'normal', num = '', render = ''):
                                 else:
                                 else:
                                     color = 'default'
                                     color = 'default'
 
 
-                            data_r += bbs_w_post_make_thread(
+                            data_r += api_topic_thread_make(
                                 for_a["ip_pas"],
                                 for_a["ip_pas"],
                                 '<a href="/thread/' + topic_num + '/comment/' + for_a["id"] + '/tool">(' + load_lang('tool') + ')</a> ' + for_a["date"],
                                 '<a href="/thread/' + topic_num + '/comment/' + for_a["id"] + '/tool">(' + load_lang('tool') + ')</a> ' + for_a["date"],
                                 for_a["data_pas"][0] + '<script>' + for_a["data_pas"][1] + '</script>',
                                 for_a["data_pas"][0] + '<script>' + for_a["data_pas"][1] + '</script>',

+ 1 - 2
route/api_w.py

@@ -11,8 +11,7 @@ def api_w(name = 'Test', tool = '', rev = ''):
                 data_pas = render_set(
                 data_pas = render_set(
                     doc_name = name, 
                     doc_name = name, 
                     doc_data = data_org, 
                     doc_data = data_org, 
-                    data_type = 'api_view',
-                    data_in = ''
+                    data_type = 'api_view'
                 )
                 )
 
 
                 return flask.jsonify({
                 return flask.jsonify({

+ 7 - 1
route/bbs_main.py

@@ -15,12 +15,18 @@ def bbs_main():
                 curs.execute(db_change('select set_data from bbs_set where set_name = "bbs_type" and set_id = ?'), [for_a[1]])
                 curs.execute(db_change('select set_data from bbs_set where set_name = "bbs_type" and set_id = ?'), [for_a[1]])
                 db_data_2 = curs.fetchall()
                 db_data_2 = curs.fetchall()
                 bbs_type = db_data_2[0][0] if db_data_2 else 'comment'
                 bbs_type = db_data_2[0][0] if db_data_2 else 'comment'
+
+                if bbs_type == 'thread':
+                    bbs_type = load_lang('thread_base')
+                else:
+                    bbs_type = load_lang('comment_base')
                 
                 
                 curs.execute(db_change('select set_data from bbs_data where set_id = ? and set_name = "date" order by set_code + 0 desc limit 1'), [for_a[1]])
                 curs.execute(db_change('select set_data from bbs_data where set_id = ? and set_name = "date" order by set_code + 0 desc limit 1'), [for_a[1]])
                 db_data_2 = curs.fetchall()
                 db_data_2 = curs.fetchall()
                 last_date = ('(' + db_data_2[0][0] + ')') if db_data_2 else ''
                 last_date = ('(' + db_data_2[0][0] + ')') if db_data_2 else ''
 
 
-                data += '<li><a href="/bbs/w/' + for_a[1] + '">' + for_a[0] + ' (' + bbs_type + ') ' + last_date + '</a></li>'
+                data += '<li><a href="/bbs/w/' + for_a[1] + '">' + html.escape(for_a[0]) + ' (' + bbs_type + ') ' + last_date + '</a></li>'
+                # data += '<li></li>'
 
 
             data += '</ul>'
             data += '</ul>'
 
 

+ 2 - 2
route/bbs_make.py

@@ -32,8 +32,8 @@ def bbs_make():
                         <hr class="main_hr">
                         <hr class="main_hr">
                         
                         
                         <select name="bbs_type">
                         <select name="bbs_type">
-                            <option value="comment">''' + load_lang('comment') + '''</option>
-                            <option value="thread">''' + load_lang('thread') + '''</option>
+                            <option value="comment">''' + load_lang('comment_base') + '''</option>
+                            <option value="thread">''' + load_lang('thread_base') + '''</option>
                         </select>
                         </select>
                         <hr class="main_hr">
                         <hr class="main_hr">
                         
                         

+ 11 - 11
route/bbs_w.py

@@ -4,17 +4,19 @@ def bbs_w(bbs_num = ''):
     with get_db_connect() as conn:
     with get_db_connect() as conn:
         curs = conn.cursor()
         curs = conn.cursor()
 
 
-        curs.execute(db_change('select set_id from bbs_set where set_id = ? and set_name = "bbs_name"'), [bbs_num])
-        if not curs.fetchall():
+        curs.execute(db_change('select set_data from bbs_set where set_id = ? and set_name = "bbs_name"'), [bbs_num])
+        db_data = curs.fetchall()
+        if not db_data:
             return redirect('/bbs/main')
             return redirect('/bbs/main')
-
+        
+        bbs_name = db_data[0][0]
         bbs_num_str = str(bbs_num)
         bbs_num_str = str(bbs_num)
 
 
         data = ''
         data = ''
         data += '''
         data += '''
             <table id="main_table_set">
             <table id="main_table_set">
                 <tr id="main_table_top_tr">
                 <tr id="main_table_top_tr">
-                    <td id="main_table_width">''' + load_lang('version') + '''</td>
+                    <td id="main_table_width">''' + load_lang('order') + '''</td>
                     <td id="main_table_width">''' + load_lang('editor') + '''</td>
                     <td id="main_table_width">''' + load_lang('editor') + '''</td>
                     <td id="main_table_width">''' + load_lang('time') + '''</td>
                     <td id="main_table_width">''' + load_lang('time') + '''</td>
                 </tr>
                 </tr>
@@ -30,10 +32,9 @@ def bbs_w(bbs_num = ''):
         for for_a in db_data + [['', '', '']]:
         for for_a in db_data + [['', '', '']]:
             if temp_id != for_a[2]:
             if temp_id != for_a[2]:
                 if temp_id != '':
                 if temp_id != '':
-                    curs.execute(db_change('select set_data from bbs_data where set_name = "comment_date" and set_id = ? order by set_code + 0 desc'), [bbs_num_str + '-' + temp_dict['code']])
+                    curs.execute(db_change('select count(*) from bbs_data where set_name = "comment_date" and (set_id = ? or set_id like ?) order by set_code + 0 desc'), [bbs_num_str + '-' + temp_dict['code'], bbs_num_str + '-' + temp_dict['code'] + '-%'])
                     db_data = curs.fetchall()
                     db_data = curs.fetchall()
-                    last_comment_date = db_data[0][0] if db_data else '0'
-                    comment_count = str(len(db_data)) if db_data else '0'
+                    comment_count = str(db_data[0][0]) if db_data else '0'
                     
                     
                     data += '''
                     data += '''
                         <tr>
                         <tr>
@@ -43,9 +44,8 @@ def bbs_w(bbs_num = ''):
                         </tr>
                         </tr>
                         <tr>
                         <tr>
                             <td colspan="3">
                             <td colspan="3">
-                                <a href="/bbs/w/''' + bbs_num_str + '/' + temp_dict['code'] + '">' + temp_dict['title'] + '''</a> 
+                                <a href="/bbs/w/''' + bbs_num_str + '/' + temp_dict['code'] + '">' + html.escape(temp_dict['title']) + '''</a> 
                                 (''' + comment_count + ''') 
                                 (''' + comment_count + ''') 
-                                (''' + last_comment_date + ''')
                             </td>
                             </td>
                         </tr>
                         </tr>
                     '''
                     '''
@@ -58,7 +58,7 @@ def bbs_w(bbs_num = ''):
         data += '</table>'
         data += '</table>'
 
 
         return easy_minify(flask.render_template(skin_check(),
         return easy_minify(flask.render_template(skin_check(),
-            imp = [load_lang('bbs_main'), wiki_set(), wiki_custom(), wiki_css([0, 0])],
+            imp = [bbs_name, wiki_set(), wiki_custom(), wiki_css(['(' + load_lang('bbs') + ')', 0])],
             data = data,
             data = data,
-            menu = [['bbs/main', load_lang('return')], ['bbs/edit/' + bbs_num_str, load_lang('add')], ['bbs/set/' + bbs_num_str, load_lang('setting')]]
+            menu = [['bbs/main', load_lang('return')], ['bbs/edit/' + bbs_num_str, load_lang('add')], ['bbs/set/' + bbs_num_str, load_lang('bbs_set')]]
         ))
         ))

+ 51 - 58
route/bbs_edit.py → route/bbs_w_edit.py

@@ -1,6 +1,9 @@
 from .tool.func import *
 from .tool.func import *
 
 
-def bbs_edit(bbs_num = '', post_num = '', do_type = ''):
+from .api_bbs_w_post import api_bbs_w_post
+from .edit import edit_editor
+
+def bbs_w_edit(bbs_num = '', post_num = '', do_type = ''):
     with get_db_connect() as conn:
     with get_db_connect() as conn:
         curs = conn.cursor()
         curs = conn.cursor()
 
 
@@ -24,6 +27,8 @@ def bbs_edit(bbs_num = '', post_num = '', do_type = ''):
             
             
         if acl_check(bbs_num_str, 'bbs_edit') == 1:
         if acl_check(bbs_num_str, 'bbs_edit') == 1:
             return redirect('/bbs/set/' + bbs_num_str)
             return redirect('/bbs/set/' + bbs_num_str)
+        
+        i_list = ['post_view_acl', 'post_comment_acl']
 
 
         if flask.request.method == 'POST' and do_type != 'preview':
         if flask.request.method == 'POST' and do_type != 'preview':
             if captcha_post(flask.request.form.get('g-recaptcha-response', flask.request.form.get('g-recaptcha', ''))) == 1:
             if captcha_post(flask.request.form.get('g-recaptcha-response', flask.request.form.get('g-recaptcha', ''))) == 1:
@@ -59,16 +64,18 @@ def bbs_edit(bbs_num = '', post_num = '', do_type = ''):
 
 
             return redirect('/bbs/w/' + bbs_num_str + '/' + id_data)
             return redirect('/bbs/w/' + bbs_num_str + '/' + id_data)
         else:
         else:
+            d_list = ['' for _ in range(0, len(i_list))]
             if do_type == 'preview':
             if do_type == 'preview':
                 title = flask.request.form.get('title', '')
                 title = flask.request.form.get('title', '')
                 data = flask.request.form.get('content', '')
                 data = flask.request.form.get('content', '')
                 data = data.replace('\r', '')
                 data = data.replace('\r', '')
-
                 data_preview = render_set(
                 data_preview = render_set(
-                    doc_name = '', 
                     doc_data = data,
                     doc_data = data,
-                    data_in = 'from'
-                )
+                    data_type = 'thread',
+                    data_in = 'bbs'
+                ) + '<hr>'
+                for for_a in range(0, len(i_list)):
+                    d_list[for_a] = flask.request.form.get(i_list[for_a], 'normal')
             else:
             else:
                 if post_num == '':
                 if post_num == '':
                     title = ''
                     title = ''
@@ -79,19 +86,22 @@ def bbs_edit(bbs_num = '', post_num = '', do_type = ''):
                     db_data = curs.fetchall()
                     db_data = curs.fetchall()
                     db_data = list(db_data) if db_data else []
                     db_data = list(db_data) if db_data else []
 
 
-                    temp_id = ''
-                    temp_dict = {}
-
-                    for for_a in db_data + [['', '', '']]:
-                        if temp_id != for_a[2]:
-                            temp_id = for_a[2]
-                            temp_dict['code'] = for_a[2]
-
-                        temp_dict[for_a[0]] = for_a[1]
+                    temp_dict = json.loads(api_bbs_w_post(bbs_num_str + '-' + post_num_str).data)
 
 
                     title = temp_dict['title']
                     title = temp_dict['title']
                     data = temp_dict['data']
                     data = temp_dict['data']
                     data_preview = ''
                     data_preview = ''
+
+            acl_div = ['' for _ in range(0, len(i_list))]
+            acl_list = get_acl_list()
+            for for_a in range(0, len(i_list)):
+                for data_list in acl_list:
+                    if data_list == d_list[for_a]:
+                        check = 'selected="selected"'
+                    else:
+                        check = ''
+
+                    acl_div[for_a] += '<option value="' + data_list + '" ' + check + '>' + (data_list if data_list != '' else 'normal') + '</option>'
             
             
             if post_num == '':
             if post_num == '':
                 form_action = 'formaction="/bbs/edit/' + bbs_num_str + '"'
                 form_action = 'formaction="/bbs/edit/' + bbs_num_str + '"'
@@ -101,64 +111,47 @@ def bbs_edit(bbs_num = '', post_num = '', do_type = ''):
                 form_action_preview = 'formaction="/bbs/edit/preview/' + bbs_num_str + '/' + post_num_str + '"'
                 form_action_preview = 'formaction="/bbs/edit/preview/' + bbs_num_str + '/' + post_num_str + '"'
     
     
             editor_top_text = '<a href="/edit_filter">(' + load_lang('edit_filter_rule') + ')</a>'
             editor_top_text = '<a href="/edit_filter">(' + load_lang('edit_filter_rule') + ')</a>'
-            
-            monaco_on = get_main_skin_set(curs, flask.session, 'main_css_monaco', ip)
-            if monaco_on == 'use':
-                editor_display = 'style="display: none;"'
-                monaco_display = ''
-                add_get_file = '''
-                    <link   rel="stylesheet"
-                            data-name="vs/editor/editor.main" 
-                            href="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.37.1/min/vs/editor/editor.main.min.css">
-                    <script src="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.37.1/min/vs/loader.min.js"></script>
-                '''
-
-                editor_top_text += ' <a href="javascript:opennamu_edit_turn_off_monaco();">(' + load_lang('turn_off_monaco') + ')</a>'
-                
-                if flask.request.cookies.get('main_css_darkmode', '0') == '1':
-                    monaco_thema = 'vs-dark'
-                else:
-                    monaco_thema = ''
-                
-                add_script = 'do_monaco_init("' + monaco_thema + '");'
-            else:
-                editor_display = ''
-                monaco_display = 'style="display: none;"'
-                add_get_file = ''
-                add_script = 'opennamu_edit_turn_off_monaco();'
 
 
             if editor_top_text != '':
             if editor_top_text != '':
                 editor_top_text += '<hr class="main_hr">'
                 editor_top_text += '<hr class="main_hr">'
+
+            if post_num == '':
+                bbs_title = load_lang('post_add')
+            else:
+                bbs_title = load_lang('post_edit')
     
     
             return easy_minify(flask.render_template(skin_check(), 
             return easy_minify(flask.render_template(skin_check(), 
-                imp = [load_lang('bbs_edit'), wiki_set(), wiki_custom(), wiki_css([0, 0])],
-                data =  editor_top_text + add_get_file + '''
-                    <form method="post">
-                        <textarea style="display: none;" id="opennamu_edit_origin" name="doc_data_org"></textarea>
-
-                        <div>''' + edit_button('opennamu_edit_textarea', 'opennamu_monaco_editor') + '''</div>
-                        
-                        <input placeholder="''' + load_lang('bbs_title') + '''" name="title" value="''' + html.escape(title) + '''">
+                imp = [bbs_title, wiki_set(), wiki_custom(), wiki_css([0, 0])],
+                data =  editor_top_text + '''
+                    <form method="post">                        
+                        <input placeholder="''' + load_lang('title') + '''" name="title" value="''' + html.escape(title) + '''">
                         <hr class="main_hr">
                         <hr class="main_hr">
 
 
-                        <div id="opennamu_monaco_editor" class="opennamu_textarea_500" ''' + monaco_display + '''></div>
-                        <textarea id="opennamu_edit_textarea" ''' + editor_display + ''' class="opennamu_textarea_500" name="content">''' + html.escape(data) + '''</textarea>
+                        ''' + edit_editor(curs, ip, data) + '''
                         <hr class="main_hr">
                         <hr class="main_hr">
                         
                         
                         ''' + captcha_get() + ip_warning() + '''
                         ''' + captcha_get() + ip_warning() + '''
                         
                         
                         <button id="opennamu_save_button" type="submit" ''' + form_action + ''' onclick="do_monaco_to_textarea(); do_stop_exit_release();">''' + load_lang('save') + '''</button>
                         <button id="opennamu_save_button" type="submit" ''' + form_action + ''' onclick="do_monaco_to_textarea(); do_stop_exit_release();">''' + load_lang('save') + '''</button>
                         <button id="opennamu_preview_button" type="submit" ''' + form_action_preview + ''' onclick="do_monaco_to_textarea(); do_stop_exit_release();">''' + load_lang('preview') + '''</button>
                         <button id="opennamu_preview_button" type="submit" ''' + form_action_preview + ''' onclick="do_monaco_to_textarea(); do_stop_exit_release();">''' + load_lang('preview') + '''</button>
-                    </form>
-                    
-                    <hr class="main_hr">
-                    <div id="opennamu_preview_area">''' + data_preview + '''</div>
                     
                     
-                    <script>
-                        do_stop_exit();
-                        do_paste_image('opennamu_edit_textarea', 'opennamu_monaco_editor');
-                        ''' + add_script + '''
-                    </script>
+                        <hr class="main_hr">
+                        <div id="opennamu_preview_area">''' + data_preview + '''</div>
+
+                        ''' + render_simple_set('''
+                            <hr class="main_hr">
+                            <a href="/acl/TEST#exp">(''' + load_lang('reference') + ''')</a>
+                            <h2>''' + load_lang('acl') + '''</h2>
+                            <h3>''' + load_lang('post_view_acl') + '''</h3>
+                            <select name="post_view_acl">''' + acl_div[0] + '''</select>
+
+                            <h4>''' + load_lang('post_comment_acl') + '''</h4>
+                            <select name="post_comment_acl">''' + acl_div[1] + '''</select>
+
+                            <h2>''' + load_lang('markup') + '''</h2>
+                            ''' + load_lang('not_working') + '''
+                        ''') + '''
+                    </form>
                 ''',
                 ''',
                 menu = [['bbs/w/' + bbs_num_str, load_lang('return')]]
                 menu = [['bbs/w/' + bbs_num_str, load_lang('return')]]
             ))
             ))

+ 184 - 195
route/bbs_w_post.py

@@ -1,44 +1,83 @@
 from .tool.func import *
 from .tool.func import *
 
 
-def bbs_w_post_make_thread(user_id, date, data, code, color = '', blind = '', add_style = ''):
-    if blind != '':
-        if data == '':
-            color_b = 'opennamu_comment_blind'
-        else:
-            color_b = 'opennamu_comment_blind_admin'
-    else:
-        color_b = 'opennamu_comment_blind_not'
-
-    return '''
-        <table class="opennamu_comment" style="''' + add_style + '''">
-            <tr>
-                <td class="opennamu_comment_color_''' + color + '''">
-                    <a href="#thread_shortcut" id="''' + code + '''">#''' + code + '''</a>
-                    ''' + user_id + '''
-                    <span style="float: right;">''' + date + '''</span>
-                </td>
-            </tr>
-            <tr>
-                <td class="''' + color_b + '''" id="opennamu_comment_data_main">
-                    ''' + data + '''
-                </td>
-            </tr>
-        </table>
-    '''
+from .api_bbs_w_post import api_bbs_w_post
+from .api_bbs_w_comment import api_bbs_w_comment
+from .api_topic import api_topic_thread_make, api_topic_thread_pre_render
+
+from .edit import edit_editor
+
+def bbs_w_post_comment(user_id, sub_code, comment_num, bbs_num_str, post_num_str):
+    comment_data = ''
+    comment_select = ''
+
+    comment_count = 0
+    comment_add_count = 0
+
+    thread_data = json.loads(api_bbs_w_comment(sub_code).data)
+    
+    comment_count += len(thread_data)
+    comment_add_count += comment_count
+
+    for temp_dict in thread_data:
+        color = 'default'
+        if user_id == temp_dict['comment_user_id']:
+            color = 'green'
+
+        sub_code_check = re.sub(r'^[0-9]+-[0-9]+-', '', sub_code + '-' + temp_dict['code'])
+        margin_count = sub_code_check.count('-')
+
+        date = ''
+        date += '<a href="javascript:opennamu_change_comment(\'' + sub_code_check + '\');">(' + load_lang('comment') + ')</a> '
+        date += '<a href="/bbs/w/' + bbs_num_str + '/' + post_num_str + '/comment/' + sub_code_check + '/tool">(' + load_lang('tool') + ')</a> '
+        date += temp_dict['comment_date']
+
+        comment_data += '<span style="padding-left: 20px;"></span>' * margin_count
+        comment_data += api_topic_thread_make(
+            ip_pas(temp_dict['comment_user_id']),
+            date,
+            render_set(
+                doc_data = temp_dict['comment'],
+                data_in = 'bbs_comment_' + sub_code_check
+            ),
+            sub_code_check,
+            color = color,
+            add_style = 'width: calc(100% - ' + str(margin_count * 20) + 'px);'
+        )
+
+        comment_default = ''
+        if comment_num == sub_code_check:
+            comment_default = 'selected'
+
+        comment_select += '<option value="' + sub_code_check + '" ' + comment_default + '>' + sub_code_check + '</option>'
+        comment_data += '<hr class="main_hr">'
+
+        temp_data = bbs_w_post_comment(user_id, sub_code + '-' + temp_dict['code'], comment_num, bbs_num_str, post_num_str)
+
+        comment_data += temp_data[0]
+        comment_select += temp_data[1]
+        comment_add_count += temp_data[3]
+
+    return (comment_data, comment_select, comment_count, comment_add_count)
 
 
 def bbs_w_post(bbs_num = '', post_num = '', do_type = ''):
 def bbs_w_post(bbs_num = '', post_num = '', do_type = ''):
     with get_db_connect() as conn:
     with get_db_connect() as conn:
         curs = conn.cursor()
         curs = conn.cursor()
 
 
-        curs.execute(db_change('select set_name, set_data, set_code from bbs_data where set_id = ? and set_code = ?'), [bbs_num, post_num])
-        db_data = curs.fetchall()
-        if not db_data:
+        curs.execute(db_change('select set_data from bbs_set where set_id = ? and set_name = "bbs_name"'), [bbs_num])
+        db_data_3 = curs.fetchall()
+        if not db_data_3:
             return redirect('/bbs/main')
             return redirect('/bbs/main')
+        
+        bbs_name = db_data_3[0][0]
 
 
         bbs_num_str = str(bbs_num)
         bbs_num_str = str(bbs_num)
         post_num_str = str(post_num)
         post_num_str = str(post_num)
         bbs_comment_acl = acl_check(bbs_num_str, 'bbs_comment')
         bbs_comment_acl = acl_check(bbs_num_str, 'bbs_comment')
         ip = ip_check()
         ip = ip_check()
+
+        temp_dict = json.loads(api_bbs_w_post(bbs_num_str + '-' + post_num_str).data)
+        if temp_dict == {}:
+            return redirect('/bbs/main')
         
         
         curs.execute(db_change('select set_data from bbs_set where set_id = ? and set_name = "bbs_type"'), [bbs_num])
         curs.execute(db_change('select set_data from bbs_set where set_id = ? and set_name = "bbs_type"'), [bbs_num])
         db_data_2 = curs.fetchall()
         db_data_2 = curs.fetchall()
@@ -57,116 +96,101 @@ def bbs_w_post(bbs_num = '', post_num = '', do_type = ''):
                 set_id = bbs_num_str + '-' + post_num_str
                 set_id = bbs_num_str + '-' + post_num_str
 
 
                 curs.execute(db_change('select set_code from bbs_data where set_name = "comment" and set_id = ? order by set_code + 0 desc'), [set_id])
                 curs.execute(db_change('select set_code from bbs_data where set_name = "comment" and set_id = ? order by set_code + 0 desc'), [set_id])
-                db_data = curs.fetchall()
-                id_data = str(int(db_data[0][0]) + 1) if db_data else '1'
+                db_data_4 = curs.fetchall()
+                id_data = str(int(db_data_4[0][0]) + 1) if db_data_4 else '1'
 
 
                 data = flask.request.form.get('content', '')
                 data = flask.request.form.get('content', '')
                 if data == '':
                 if data == '':
                     # re_error로 대체 예정
                     # re_error로 대체 예정
                     return redirect('/bbs/w/' + bbs_num_str + '/' + post_num_str)
                     return redirect('/bbs/w/' + bbs_num_str + '/' + post_num_str)
                 
                 
+                data = data.replace('\r', '')
+                data = api_topic_thread_pre_render(curs, data, id_data, ip, set_id, bbs_name, temp_dict['title'], 'post')
+                
                 date = get_time()
                 date = get_time()
 
 
                 curs.execute(db_change("insert into bbs_data (set_name, set_code, set_id, set_data) values ('comment', ?, ?, ?)"), [id_data, set_id, data])
                 curs.execute(db_change("insert into bbs_data (set_name, set_code, set_id, set_data) values ('comment', ?, ?, ?)"), [id_data, set_id, data])
                 curs.execute(db_change("insert into bbs_data (set_name, set_code, set_id, set_data) values ('comment_date', ?, ?, ?)"), [id_data, set_id, date])
                 curs.execute(db_change("insert into bbs_data (set_name, set_code, set_id, set_data) values ('comment_date', ?, ?, ?)"), [id_data, set_id, date])
                 curs.execute(db_change("insert into bbs_data (set_name, set_code, set_id, set_data) values ('comment_user_id', ?, ?, ?)"), [id_data, set_id, ip])
                 curs.execute(db_change("insert into bbs_data (set_name, set_code, set_id, set_data) values ('comment_user_id', ?, ?, ?)"), [id_data, set_id, ip])
 
 
+                add_alarm(temp_dict['user_id'], ip, 'BBS <a href="/bbs/w/' + bbs_num_str + '/' + post_num_str + '#' + id_data + '">' + html.escape(bbs_name) + ' - ' + html.escape(temp_dict['title']) + '#' + id_data + '</a>')
+
                 conn.commit()
                 conn.commit()
 
 
-                return redirect('/bbs/w/' + bbs_num_str + '/' + post_num_str + '#comment_' + str(int(id_data) + 1))
+                return redirect('/bbs/w/' + bbs_num_str + '/' + post_num_str + '#' + id_data)
             else:
             else:
                 if acl_check(bbs_num_str, 'bbs_view') == 1:
                 if acl_check(bbs_num_str, 'bbs_view') == 1:
                     return re_error('/ban')
                     return re_error('/ban')
 
 
+                text = ''
+                data_preview = ''
                 if do_type == 'preview':
                 if do_type == 'preview':
                     text = flask.request.form.get('content', '')
                     text = flask.request.form.get('content', '')
                     text = text.replace('\r', '')
                     text = text.replace('\r', '')
 
 
                     data_preview = render_set(
                     data_preview = render_set(
-                        doc_name = '', 
                         doc_data = text,
                         doc_data = text,
-                        data_in = 'from'
+                        data_type = 'thread',
+                        data_in = 'bbs_comment_preview'
                     )
                     )
-                else:
-                    text = ''
-                    data_preview = ''
-                
-                temp_id = ''
-                temp_dict = {}
-
-                db_data = list(db_data) if db_data else []
-                for for_a in db_data + [['', '', '']]:
-                    if temp_id != for_a[2]:
-                        temp_id = for_a[2]
-                        temp_dict['code'] = for_a[2]
 
 
-                    temp_dict[for_a[0]] = for_a[1]
-
-                count = 1
+                date = ''
+                date += '<a href="/bbs/w/' + bbs_num_str + '/' + post_num_str + '/tool">(' + load_lang('tool') + ')</a> '
+                date += temp_dict['date']
 
 
                 data = ''
                 data = ''
                 data += '<h2>' + html.escape(temp_dict['title']) + '</h2>'
                 data += '<h2>' + html.escape(temp_dict['title']) + '</h2>'
-                data += bbs_w_post_make_thread(
+                data += api_topic_thread_make(
                     ip_pas(temp_dict['user_id']),
                     ip_pas(temp_dict['user_id']),
-                    temp_dict['date'],
+                    date,
                     render_set(
                     render_set(
-                        doc_name = '', 
                         doc_data = temp_dict['data'],
                         doc_data = temp_dict['data'],
-                        data_in = 'from'
+                        data_type = 'thread',
+                        data_in = 'bbs'
                     ),
                     ),
-                    '1',
+                    '0',
                     color = 'green'
                     color = 'green'
                 )
                 )
                 data += '<hr class="main_hr">'
                 data += '<hr class="main_hr">'
 
 
                 user_id = temp_dict['user_id']
                 user_id = temp_dict['user_id']
+                count = 0
 
 
-                temp_id = ''
-                temp_dict = {}
-
-                curs.execute(db_change('select set_name, set_data, set_code, set_id from bbs_data where (set_name = "comment" or set_name = "comment_date" or set_name = "comment_user_id") and set_id = ? order by set_code + 0 asc'), [bbs_num_str + '-' + post_num_str])
-                db_data = curs.fetchall()
-                db_data = list(db_data) if db_data else []
-
-                for for_a in db_data + [['', '', '']]:
-                    if temp_id == '':
-                        temp_id = for_a[2]
-
-                    if temp_id != for_a[2]:
-                        temp_id = for_a[2]
-                        temp_dict['code'] = for_a[2]
-                        count += 1
-
-                        if user_id == temp_dict['comment_user_id']:
-                            color = 'green'
-                        else:
-                            color = 'default'
-
-                        data += bbs_w_post_make_thread(
-                            ip_pas(temp_dict['comment_user_id']),
-                            temp_dict['comment_date'],
-                            render_set(
-                                doc_name = '', 
-                                doc_data = temp_dict['comment'],
-                                data_in = 'from'
-                            ),
-                            str(count),
-                            color = color
-                        )
-                        data += '<hr class="main_hr">'
-
-                    temp_dict[for_a[0]] = for_a[1]
+                thread_data = json.loads(api_bbs_w_comment(bbs_num_str + '-' + post_num_str).data)
+                for temp_dict in thread_data:
+                    count += 1
+                    if user_id == temp_dict['comment_user_id']:
+                        color = 'green'
+                    else:
+                        color = 'default'
+                        
+                    date = ''
+                    date += '<a href="/bbs/w/' + bbs_num_str + '/' + post_num_str + '/comment/' + str(count) + '/tool">(' + load_lang('tool') + ')</a> '
+                    date += temp_dict['comment_date']
+
+                    data += api_topic_thread_make(
+                        ip_pas(temp_dict['comment_user_id']),
+                        date,
+                        render_set(
+                            doc_data = temp_dict['comment'],
+                            data_type = 'thread',
+                            data_in = 'bbs_comment_' + str(count)
+                        ),
+                        str(count),
+                        color = color
+                    )
+                    data += '<hr class="main_hr">'
 
 
                 bbs_comment_form = ''
                 bbs_comment_form = ''
                 if bbs_comment_acl == 0:
                 if bbs_comment_acl == 0:
-                    bbs_comment_form = '''                        
-                        <textarea name="content" id="opennamu_edit_textarea" class="opennamu_textarea_100">''' + html.escape(text) + '''</textarea>
+                    bbs_comment_form += '''                        
+                        ''' + edit_editor(curs, ip, text, 'thread') + '''
                         <hr class="main_hr">
                         <hr class="main_hr">
                         
                         
                         ''' + captcha_get() + ip_warning() + '''
                         ''' + captcha_get() + ip_warning() + '''
 
 
-                        <button id="opennamu_save_button" formaction="/bbs/w/''' + bbs_num_str + '''/''' + post_num_str + '''" type="submit">''' + load_lang('send') + '''</button>
-                        <button id="opennamu_preview_button" formaction="/bbs/w/preview/''' + bbs_num_str + '''/''' + post_num_str + '''#opennamu_edit_textarea" type="submit">''' + load_lang('preview') + '''</button>
+                        <button id="opennamu_save_button" formaction="/bbs/w/''' + bbs_num_str + '''/''' + post_num_str + '''" type="submit" onclick="do_monaco_to_textarea(); do_stop_exit_release();">''' + load_lang('send') + '''</button>
+                        <button id="opennamu_preview_button" formaction="/bbs/w/preview/''' + bbs_num_str + '''/''' + post_num_str + '''#opennamu_edit_textarea" type="submit" onclick="do_monaco_to_textarea(); do_stop_exit_release();">''' + load_lang('preview') + '''</button>
                         <hr class="main_hr">
                         <hr class="main_hr">
                     '''
                     '''
 
 
@@ -178,7 +202,7 @@ def bbs_w_post(bbs_num = '', post_num = '', do_type = ''):
                 '''
                 '''
 
 
                 return easy_minify(flask.render_template(skin_check(),
                 return easy_minify(flask.render_template(skin_check(),
-                    imp = [load_lang('bbs_main'), wiki_set(), wiki_custom(), wiki_css([0, 0])],
+                    imp = [bbs_name, wiki_set(), wiki_custom(), wiki_css(['(' + load_lang('bbs') + ')', 0])],
                     data = data,
                     data = data,
                     menu = [['bbs/w/' + bbs_num_str, load_lang('return')], ['bbs/edit/' + bbs_num_str + '/' + post_num_str, load_lang('edit')]]
                     menu = [['bbs/w/' + bbs_num_str, load_lang('return')], ['bbs/edit/' + bbs_num_str + '/' + post_num_str, load_lang('edit')]]
                 ))
                 ))
@@ -193,28 +217,36 @@ def bbs_w_post(bbs_num = '', post_num = '', do_type = ''):
                 else:
                 else:
                     captcha_post('', 0)
                     captcha_post('', 0)
                 
                 
-                select = flask.request.form.get('comment_select', 'default')
-                select = '' if select == 'default' else select
+                select = flask.request.form.get('comment_select', '0')
+                select = '' if select == '0' else select
+
+                comment_user_name = ''
+
                 if select != '':
                 if select != '':
-                    select = select.split('-')
-                    if len(select) < 2:
-                        curs.execute(db_change('select set_code from bbs_data where set_name = "comment" and set_id = ? and set_code = ? limit 1'), [bbs_num_str + '-' + post_num_str, select[0]])
-                        if not curs.fetchall():
-                            return ''
+                    select_split = select.split('-')
+                    if len(select_split) < 2:
+                        curs.execute(db_change('select set_data from bbs_data where set_name = "comment_user_id" and set_id = ? and set_code = ? limit 1'), [bbs_num_str + '-' + post_num_str, select_split[0]])    
+                        db_data_6 = curs.fetchall()
+                        if not db_data_6:
+                            # re_error로 변경 예정
+                            return redirect('/bbs/w/' + bbs_num_str + '/' + post_num_str)
                         else:
                         else:
-                            set_id = bbs_num_str + '-' + post_num_str + '-' + select[0]
+                            set_id = bbs_num_str + '-' + post_num_str + '-' + select_split[0]
+                            comment_user_name = db_data_6[0][0]
                     else:
                     else:
-                        curs.execute(db_change('select set_code from bbs_data where set_name = "comment" and set_id = ? and set_code = ? limit 1'), [bbs_num_str + '-' + post_num_str + '-' + '-'.join(select[0:len(select) - 1]), select[len(select) - 1]])
-                        if not curs.fetchall():
-                            return ''
+                        curs.execute(db_change('select set_data from bbs_data where set_name = "comment_user_id" and set_id = ? and set_code = ? limit 1'), [bbs_num_str + '-' + post_num_str + '-' + '-'.join(select_split[0:len(select_split) - 1]), select_split[len(select_split) - 1]])
+                        db_data_7 = curs.fetchall()
+                        if not db_data_7:
+                            return redirect('/bbs/w/' + bbs_num_str + '/' + post_num_str)
                         else:
                         else:
-                            set_id = bbs_num_str + '-' + post_num_str + '-' + '-'.join(select)
+                            set_id = bbs_num_str + '-' + post_num_str + '-' + '-'.join(select_split)
+                            comment_user_name = db_data_7[0][0]
                 else:
                 else:
                     set_id = bbs_num_str + '-' + post_num_str
                     set_id = bbs_num_str + '-' + post_num_str
 
 
-                curs.execute(db_change('select set_code from bbs_data where set_name = "comment" and set_id = ? order by set_code + 0 desc'), [set_id])
-                db_data = curs.fetchall()
-                id_data = str(int(db_data[0][0]) + 1) if db_data else '1'
+                curs.execute(db_change('select set_code from bbs_data where set_name = "comment" and set_id = ? order by set_code + 0 desc limit 1'), [set_id])
+                db_data_5 = curs.fetchall()
+                id_data = str(int(db_data_5[0][0]) + 1) if db_data_5 else '1'
 
 
                 data = flask.request.form.get('content', '')
                 data = flask.request.form.get('content', '')
                 if data == '':
                 if data == '':
@@ -230,138 +262,94 @@ def bbs_w_post(bbs_num = '', post_num = '', do_type = ''):
                 conn.commit()
                 conn.commit()
             
             
                 if set_id == '':
                 if set_id == '':
-                    return redirect('/bbs/w/' + bbs_num_str + '/' + post_num_str + '#comment_' + id_data)
+                    end_id = id_data
                 else:
                 else:
                     set_id = re.sub(r'^[0-9]+-[0-9]+-?', '', set_id)
                     set_id = re.sub(r'^[0-9]+-[0-9]+-?', '', set_id)
-                    return redirect('/bbs/w/' + bbs_num_str + '/' + post_num_str + '#comment_' + set_id + '-' + id_data)
+                    set_id += '-' if set_id != '' else ''
+                    end_id = set_id + id_data
+
+                add_alarm(temp_dict['user_id'], ip, 'BBS <a href="/bbs/w/' + bbs_num_str + '/' + post_num_str + '#' + end_id + '">' + html.escape(bbs_name) + ' - ' + html.escape(temp_dict['title']) + '#' + end_id + '</a>')
+                if comment_user_name != '':
+                    add_alarm(comment_user_name, ip, 'BBS <a href="/bbs/w/' + bbs_num_str + '/' + post_num_str + '#' + end_id + '">' + html.escape(bbs_name) + ' - ' + html.escape(temp_dict['title']) + '#' + end_id + '</a>')
+
+                return redirect('/bbs/w/' + bbs_num_str + '/' + post_num_str + '#' + end_id)
             else:
             else:
                 if acl_check(bbs_num_str, 'bbs_view') == 1:
                 if acl_check(bbs_num_str, 'bbs_view') == 1:
                     return re_error('/ban')
                     return re_error('/ban')
                     
                     
+                text = ''
+                comment_num = ''
+                data_preview = ''
                 if do_type == 'preview':
                 if do_type == 'preview':
                     text = flask.request.form.get('content', '')
                     text = flask.request.form.get('content', '')
                     text = text.replace('\r', '')
                     text = text.replace('\r', '')
 
 
+                    comment_num = flask.request.form.get('comment_select', '')
+
                     data_preview = render_set(
                     data_preview = render_set(
-                        doc_name = '', 
                         doc_data = text,
                         doc_data = text,
-                        data_in = 'from'
+                        data_in = 'bbs_comment_preview'
                     )
                     )
-                else:
-                    text = ''
-                    data_preview = ''
-
-                temp_id = ''
-                temp_dict = {}
-
-                db_data = list(db_data) if db_data else []
-                for for_a in db_data + [['', '', '']]:
-                    if temp_id != for_a[2]:
-                        temp_id = for_a[2]
-                        temp_dict['code'] = for_a[2]
 
 
-                    temp_dict[for_a[0]] = for_a[1]
+                date = ''
+                date += '<a href="javascript:opennamu_change_comment(\'0\');">(' + load_lang('comment') + ')</a> '
+                date += '<a href="/bbs/w/' + bbs_num_str + '/' + post_num_str + '/tool">(' + load_lang('tool') + ')</a> '
+                date += temp_dict['date']
 
 
                 data = ''
                 data = ''
                 data += '<h2>' + html.escape(temp_dict['title']) + '</h2>'
                 data += '<h2>' + html.escape(temp_dict['title']) + '</h2>'
-                data += bbs_w_post_make_thread(
+                data += api_topic_thread_make(
                     ip_pas(temp_dict['user_id']),
                     ip_pas(temp_dict['user_id']),
-                    temp_dict['date'],
+                    date,
                     render_set(
                     render_set(
-                        doc_name = '', 
                         doc_data = temp_dict['data'],
                         doc_data = temp_dict['data'],
-                        data_in = 'from'
+                        data_in = 'bbs'
                     ),
                     ),
                     '0',
                     '0',
                     color = 'red'
                     color = 'red'
                 )
                 )
 
 
                 user_id = temp_dict['user_id']
                 user_id = temp_dict['user_id']
-                temp_id = ''
-                temp_dict = {}
                 comment_data = ''
                 comment_data = ''
 
 
-                comment_select = '<hr class="main_hr"><select name="comment_select">'
-                comment_select += '<option value="default">' + load_lang('normal') + '</option>'
-
-                curs.execute(db_change('select set_name, set_data, set_code, set_id from bbs_data where (set_name = "comment" or set_name = "comment_date" or set_name = "comment_user_id") and set_id = ? order by set_code + 0 asc'), [bbs_num_str + '-' + post_num_str])
-                db_data = curs.fetchall()
-                if db_data:
-                    data += '<hr class="main_hr"><hr>'
-                else:
-                    db_data = []
+                comment_select = '<select id="opennamu_comment_select" name="comment_select">'
+                comment_select += '<option value="0">' + load_lang('normal') + '</option>'
 
 
-                for_a = 0
-                db_data_2 = db_data + [['', '', '', '']]
-                db_data_len = len(db_data_2)
                 comment_count = 0
                 comment_count = 0
                 comment_add_count = 0
                 comment_add_count = 0
-                while(for_a < db_data_len):
-                    if temp_id != (db_data_2[for_a][3] + '-' + db_data_2[for_a][2]):
-                        if temp_id != '':
-                            temp_dict['code'] = temp_id
-                            temp_dict['code'] = re.sub(r'^[0-9]+-[0-9]+-', '', temp_dict['code'])
-
-                            if user_id == temp_dict['comment_user_id']:
-                                color = 'green'
-                            else:
-                                color = 'default'
-
-                            margin_count = temp_dict['code'].count('-')
-                            if margin_count == 0:
-                                comment_count += 1
-                            else:
-                                comment_add_count += 1
-
-                            comment_data += '<span style="padding-left: 20px;"></span>' * margin_count
-                            comment_data += bbs_w_post_make_thread(
-                                ip_pas(temp_dict['comment_user_id']),
-                                temp_dict['comment_date'],
-                                render_set(
-                                    doc_name = '', 
-                                    doc_data = temp_dict['comment'],
-                                    data_in = 'from'
-                                ),
-                                temp_dict['code'],
-                                color = color,
-                                add_style = 'width: calc(100% - ' + str(margin_count * 20) + 'px);'
-                            )
-
-                            comment_select += '<option value="' + temp_dict['code'] + '">' + temp_dict['code'] + '</option>'
-
-                            curs.execute(db_change('select set_name, set_data, set_code, set_id from bbs_data where (set_name = "comment" or set_name = "comment_date" or set_name = "comment_user_id") and set_id = ? order by set_code + 0 asc'), [bbs_num_str + '-' + post_num_str + '-' + temp_dict['code']])
-                            db_data = curs.fetchall()
-                            if db_data:
-                                db_data_2 = db_data_2[:for_a] + db_data + db_data_2[for_a:]
-                                db_data_len += len(db_data)
-
-                            if db_data_2[for_a][0] != '':
-                                comment_data += '<hr class="main_hr">'
-
-                        temp_id = db_data_2[for_a][3] + '-' + db_data_2[for_a][2]
-
-                    temp_dict[db_data_2[for_a][0]] = db_data_2[for_a][1]
-                    for_a += 1
+
+                temp_data = bbs_w_post_comment(user_id, bbs_num_str + '-' + post_num_str, comment_num, bbs_num_str, post_num_str)
+
+                comment_data += temp_data[0]
+                comment_select += temp_data[1]
+                comment_count += temp_data[2]
+                comment_add_count += temp_data[3]
+                comment_add_count -= comment_count
+
+                if comment_data != '':
+                    data += '<hr class="main_hr"><hr>'
 
 
                 comment_select += '</select>'
                 comment_select += '</select>'
                 if comment_data != '':
                 if comment_data != '':
                     data += load_lang('comment') + ' : ' + str(comment_count) + '<hr class="main_hr">'
                     data += load_lang('comment') + ' : ' + str(comment_count) + '<hr class="main_hr">'
                     data += load_lang('reply') + ' : ' + str(comment_add_count) + '<hr class="main_hr">'
                     data += load_lang('reply') + ' : ' + str(comment_add_count) + '<hr class="main_hr">'
                     data += comment_data
                     data += comment_data
+                else:
+                    data += '<hr class="main_hr">'
 
 
                 bbs_comment_form = ''
                 bbs_comment_form = ''
                 if bbs_comment_acl == 0:
                 if bbs_comment_acl == 0:
-                    bbs_comment_form = '''
-                        ''' + comment_select + '''
+                    bbs_comment_form += '''
+                        ''' + comment_select + ''' <a href="javascript:opennamu_return_comment();">(R)</a>
                         <hr class="main_hr">
                         <hr class="main_hr">
                         
                         
-                        <textarea name="content" id="opennamu_edit_textarea" class="opennamu_textarea_100">''' + html.escape(text) + '''</textarea>
+                        ''' + edit_editor(curs, ip, text, 'thread') + '''
                         <hr class="main_hr">
                         <hr class="main_hr">
                         
                         
                         ''' + captcha_get() + ip_warning() + '''
                         ''' + captcha_get() + ip_warning() + '''
 
 
-                        <button id="opennamu_save_button" formaction="/bbs/w/''' + bbs_num_str + '''/''' + post_num_str + '''" type="submit">''' + load_lang('send') + '''</button>
-                        <button id="opennamu_preview_button" formaction="/bbs/w/preview/''' + bbs_num_str + '''/''' + post_num_str + '''#opennamu_edit_textarea" type="submit">''' + load_lang('preview') + '''</button>
+                        <button id="opennamu_save_button" formaction="/bbs/w/''' + bbs_num_str + '''/''' + post_num_str + '''" type="submit" onclick="do_monaco_to_textarea(); do_stop_exit_release();">''' + load_lang('send') + '''</button>
+                        <button id="opennamu_preview_button" formaction="/bbs/w/preview/''' + bbs_num_str + '''/''' + post_num_str + '''#opennamu_edit_textarea" type="submit" onclick="do_monaco_to_textarea(); do_stop_exit_release();">''' + load_lang('preview') + '''</button>
                         <hr class="main_hr">
                         <hr class="main_hr">
                     '''
                     '''
 
 
@@ -370,10 +358,11 @@ def bbs_w_post(bbs_num = '', post_num = '', do_type = ''):
                         ''' + bbs_comment_form + '''
                         ''' + bbs_comment_form + '''
                         ''' + data_preview + '''
                         ''' + data_preview + '''
                     </form>
                     </form>
+                    <script src="/views/main_css/js/route/bbs_w_post.js"></script>
                 '''
                 '''
 
 
                 return easy_minify(flask.render_template(skin_check(),
                 return easy_minify(flask.render_template(skin_check(),
-                    imp = [load_lang('bbs_main'), wiki_set(), wiki_custom(), wiki_css([0, 0])],
+                    imp = [bbs_name, wiki_set(), wiki_custom(), wiki_css(['(' + load_lang('bbs') + ')', 0])],
                     data = data,
                     data = data,
                     menu = [['bbs/w/' + bbs_num_str, load_lang('return')], ['bbs/edit/' + bbs_num_str + '/' + post_num_str, load_lang('edit')]]
                     menu = [['bbs/w/' + bbs_num_str, load_lang('return')], ['bbs/edit/' + bbs_num_str + '/' + post_num_str, load_lang('edit')]]
                 ))
                 ))

+ 24 - 26
route/bbs_w_set.py

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

+ 91 - 54
route/edit.py

@@ -1,5 +1,79 @@
+import multiprocessing
+
 from .tool.func import *
 from .tool.func import *
 
 
+
+def edit_render_set(name, content):
+    render_set(
+        doc_name = name,
+        doc_data = content
+    )
+
+# https://stackoverflow.com/questions/13821156/timeout-function-using-threading-in-python-does-not-work
+def edit_timeout(func, args = (), timeout = 3):
+    pool = multiprocessing.Pool(processes = 1)
+    result = pool.apply_async(func, args = args)
+    try:
+        result.get(timeout = timeout)
+    except multiprocessing.TimeoutError:
+        pool.terminate()
+        return 1
+    else:
+        pool.close()
+        pool.join()
+        return 0
+        
+def edit_editor(curs, ip, data_main = '', do_type = 'edit'):
+    monaco_editor_top = ''
+    editor_display = ''
+    add_get_file = ''
+    monaco_display = ''
+
+    curs.execute(db_change('select data from other where name = "edit_help"'))
+    sql_d = curs.fetchall()
+    p_text = html.escape(sql_d[0][0]) if sql_d and sql_d[0][0] != '' else load_lang('default_edit_help')
+    
+    monaco_on = get_main_skin_set(curs, flask.session, 'main_css_monaco', ip)
+    if monaco_on == 'use':
+        editor_display = 'style="display: none;"'
+        add_get_file = '''
+            <link   rel="stylesheet"
+                    data-name="vs/editor/editor.main" 
+                    href="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.37.1/min/vs/editor/editor.main.min.css">
+            <script src="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.37.1/min/vs/loader.min.js"></script>
+        '''
+
+        monaco_editor_top = '<a href="javascript:opennamu_edit_turn_off_monaco();">(' + load_lang('turn_off_monaco') + ')</a>'
+        
+        if flask.request.cookies.get('main_css_darkmode', '0') == '1':
+            monaco_thema = 'vs-dark'
+        else:
+            monaco_thema = ''
+        
+        add_script = 'do_monaco_init("' + monaco_thema + '");'
+    else:
+        monaco_display = 'style="display: none;"'
+        add_script = 'opennamu_edit_turn_off_monaco();'
+
+    if do_type == 'edit':
+        textarea_size = 'opennamu_textarea_500'
+    else:
+        textarea_size = 'opennamu_textarea_100'
+
+    return add_get_file + '''
+        <textarea style="display: none;" id="opennamu_edit_origin" name="doc_data_org">''' + html.escape(data_main) + '''</textarea>
+        <div>''' + monaco_editor_top + ' ' + edit_button('opennamu_edit_textarea', 'opennamu_monaco_editor') + '''</div>
+        
+        <div id="opennamu_monaco_editor" class="''' + textarea_size + '''" ''' + monaco_display + '''></div>
+        <textarea id="opennamu_edit_textarea" ''' + editor_display + ''' class="''' + textarea_size + '''" name="content" placeholder="''' + p_text + '''">''' + html.escape(data_main) + '''</textarea>
+        <hr class="main_hr">
+        <script>
+            do_stop_exit();
+            do_paste_image('opennamu_edit_textarea', 'opennamu_monaco_editor');
+            ''' + add_script + '''
+        </script>
+    '''
+
 def edit(name = 'Test', section = 0, do_type = ''):
 def edit(name = 'Test', section = 0, do_type = ''):
     with get_db_connect() as conn:
     with get_db_connect() as conn:
         curs = conn.cursor()
         curs = conn.cursor()
@@ -74,12 +148,18 @@ def edit(name = 'Test', section = 0, do_type = ''):
             else:
             else:
                 leng = '+' + str(len(content))
                 leng = '+' + str(len(content))
 
 
-            render_set(
-                doc_name = name,
-                doc_data = content,
-                data_in = ''
-            )
-                
+            curs.execute(db_change("select data from other where name = 'edit_timeout'"))
+            db_data_2 = curs.fetchall()
+            db_data_2 = '' if not db_data_2 else number_check(db_data_2[0][0])
+
+            if db_data_2 != '' and platform.system() == 'Linux':
+                timeout = edit_timeout(edit_render_set, (name, content), timeout = int(db_data_2))
+            else:
+                timeout = 0
+
+            if timeout == 1:
+                return re_error('/error/41')
+            
             if db_data:
             if db_data:
                 curs.execute(db_change("update data set data = ? where title = ?"), [content, name])
                 curs.execute(db_change("update data set data = ? where title = ?"), [content, name])
             else:    
             else:    
@@ -90,7 +170,7 @@ def edit(name = 'Test', section = 0, do_type = ''):
     
     
             curs.execute(db_change("select user from scan where title = ? and type = ''"), [name])
             curs.execute(db_change("select user from scan where title = ? and type = ''"), [name])
             for scan_user in curs.fetchall():
             for scan_user in curs.fetchall():
-                add_alarm(scan_user[0], ip + ' | <a href="/w/' + url_pas(name) + '">' + html.escape(name) + '</a> | Edit')
+                add_alarm(scan_user[0], ip, '<a href="/w/' + url_pas(name) + '">' + html.escape(name) + '</a>')
                     
                     
             history_plus(
             history_plus(
                 name,
                 name,
@@ -209,7 +289,7 @@ def edit(name = 'Test', section = 0, do_type = ''):
                     data_preview = render_set(
                     data_preview = render_set(
                         doc_name = name, 
                         doc_name = name, 
                         doc_data = data,
                         doc_data = data,
-                        data_in = 'from'
+                        data_type = 'from'
                     )
                     )
 
 
             if data_section == '':
             if data_section == '':
@@ -224,58 +304,21 @@ def edit(name = 'Test', section = 0, do_type = ''):
     
     
             editor_top_text += '<a href="/edit_filter">(' + load_lang('edit_filter_rule') + ')</a>'
             editor_top_text += '<a href="/edit_filter">(' + load_lang('edit_filter_rule') + ')</a>'
     
     
-            curs.execute(db_change('select data from other where name = "edit_help"'))
-            sql_d = curs.fetchall()
-            p_text = html.escape(sql_d[0][0]) if sql_d and sql_d[0][0] != '' else load_lang('default_edit_help')
-            
-            monaco_on = get_main_skin_set(curs, flask.session, 'main_css_monaco', ip)
-            if monaco_on == 'use':
-                editor_display = 'style="display: none;"'
-                monaco_display = ''
-                add_get_file = '''
-                    <link   rel="stylesheet"
-                            data-name="vs/editor/editor.main" 
-                            href="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.37.1/min/vs/editor/editor.main.min.css">
-                    <script src="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.37.1/min/vs/loader.min.js"></script>
-                '''
-
-                editor_top_text += ' <a href="javascript:opennamu_edit_turn_off_monaco();">(' + load_lang('turn_off_monaco') + ')</a>'
-                
-                if flask.request.cookies.get('main_css_darkmode', '0') == '1':
-                    monaco_thema = 'vs-dark'
-                else:
-                    monaco_thema = ''
-                
-                add_script = 'do_monaco_init("' + monaco_thema + '");'
-            else:
-                editor_display = ''
-                monaco_display = 'style="display: none;"'
-                add_get_file = ''
-                add_script = 'opennamu_edit_turn_off_monaco();'
-
             if editor_top_text != '':
             if editor_top_text != '':
                 editor_top_text += '<hr class="main_hr">'
                 editor_top_text += '<hr class="main_hr">'
 
 
             sub_menu = ' (' + str(section) + ')' if section != '' else ''
             sub_menu = ' (' + str(section) + ')' if section != '' else ''
-    
+
             return easy_minify(flask.render_template(skin_check(), 
             return easy_minify(flask.render_template(skin_check(), 
                 imp = [name, wiki_set(), wiki_custom(), wiki_css(['(' + load_lang('edit') + ')' + sub_menu, 0])],
                 imp = [name, wiki_set(), wiki_custom(), wiki_css(['(' + load_lang('edit') + ')' + sub_menu, 0])],
-                data =  editor_top_text + add_get_file + '''
-                    <script>
-                        
-                    </script>
+                data = editor_top_text + '''
                     <form method="post">
                     <form method="post">
-                        <textarea style="display: none;" id="opennamu_edit_origin" name="doc_data_org">''' + html.escape(data_section) + '''</textarea>
                         <textarea style="display: none;" name="doc_section_data_where">''' + data_section_where + '''</textarea>
                         <textarea style="display: none;" name="doc_section_data_where">''' + data_section_where + '''</textarea>
                         <input style="display: none;" name="doc_section_edit_apply" value="''' + doc_section_edit_apply + '''">
                         <input style="display: none;" name="doc_section_edit_apply" value="''' + doc_section_edit_apply + '''">
 
 
                         <input style="display: none;" name="ver" value="''' + doc_ver + '''">
                         <input style="display: none;" name="ver" value="''' + doc_ver + '''">
                         
                         
-                        <div>''' + edit_button('opennamu_edit_textarea', 'opennamu_monaco_editor') + '''</div>
-                        
-                        <div id="opennamu_monaco_editor" class="opennamu_textarea_500" ''' + monaco_display + '''></div>
-                        <textarea id="opennamu_edit_textarea" ''' + editor_display + ''' class="opennamu_textarea_500" name="content" placeholder="''' + p_text + '''">''' + html.escape(data_section) + '''</textarea>
-                        <hr class="main_hr">
+                        ''' + edit_editor(curs, ip, data_section) + '''
 
 
                         <input placeholder="''' + load_lang('why') + '''" name="send">
                         <input placeholder="''' + load_lang('why') + '''" name="send">
                         <hr class="main_hr">
                         <hr class="main_hr">
@@ -288,12 +331,6 @@ def edit(name = 'Test', section = 0, do_type = ''):
                     
                     
                     <hr class="main_hr">
                     <hr class="main_hr">
                     <div id="opennamu_preview_area">''' + data_preview + '''</div>
                     <div id="opennamu_preview_area">''' + data_preview + '''</div>
-                    
-                    <script>
-                        do_stop_exit();
-                        do_paste_image('opennamu_edit_textarea', 'opennamu_monaco_editor');
-                        ''' + add_script + '''
-                    </script>
                 ''',
                 ''',
                 menu = [
                 menu = [
                     ['w/' + url_pas(name), load_lang('return')],
                     ['w/' + url_pas(name), load_lang('return')],

+ 10 - 12
route/edit_delete_file.py

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

+ 1 - 0
route/edit_delete_multiple.py

@@ -1,4 +1,5 @@
 from .tool.func import *
 from .tool.func import *
+
 from .edit_delete import edit_delete
 from .edit_delete import edit_delete
 
 
 def edit_delete_multiple():
 def edit_delete_multiple():

+ 1 - 1
route/give_admin_groups.py

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

+ 1 - 1
route/give_delete_admin_group.py

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

+ 3 - 4
route/list_image_file.py

@@ -1,11 +1,10 @@
 from .tool.func import *
 from .tool.func import *
 
 
-def list_image_file():
+def list_image_file(arg_num = 1):
     with get_db_connect() as conn:
     with get_db_connect() as conn:
         curs = conn.cursor()
         curs = conn.cursor()
 
 
-        num = int(number_check(flask.request.args.get('num', '1')))
-        sql_num = (num * 50 - 50) if num * 50 > 0 else 0
+        sql_num = (arg_num * 50 - 50) if arg_num * 50 > 0 else 0
 
 
         list_data = '<ul class="opennamu_ul">'
         list_data = '<ul class="opennamu_ul">'
 
 
@@ -14,7 +13,7 @@ def list_image_file():
         for data in data_list:
         for data in data_list:
             list_data += '<li><a href="/w/' + url_pas(data[0]) + '">' + html.escape(data[0]) + '</a></li>'
             list_data += '<li><a href="/w/' + url_pas(data[0]) + '">' + html.escape(data[0]) + '</a></li>'
 
 
-        list_data += next_fix('/list/file/', num, data_list)
+        list_data += next_fix('/list/file/', arg_num, data_list)
 
 
         return easy_minify(flask.render_template(skin_check(),
         return easy_minify(flask.render_template(skin_check(),
             imp = [load_lang('image_file_list'), wiki_set(), wiki_custom(), wiki_css([0, 0])],
             imp = [load_lang('image_file_list'), wiki_set(), wiki_custom(), wiki_css([0, 0])],

+ 8 - 5
route/list_long_page.py

@@ -1,9 +1,11 @@
 from .tool.func import *
 from .tool.func import *
 
 
-def list_long_page(tool = 'long_page'):
+def list_long_page(tool = 'long_page', arg_num = 1):
     with get_db_connect() as conn:
     with get_db_connect() as conn:
         curs = conn.cursor()
         curs = conn.cursor()
 
 
+        sql_num = (arg_num * 50 - 50) if arg_num * 50 > 0 else 0
+
         curs.execute(db_change('select data from other where name = "count_all_title"'))
         curs.execute(db_change('select data from other where name = "count_all_title"'))
         if int(curs.fetchall()[0][0]) > 30000:
         if int(curs.fetchall()[0][0]) > 30000:
             return re_error('/error/25')
             return re_error('/error/25')
@@ -12,11 +14,12 @@ def list_long_page(tool = 'long_page'):
         select_data = 'desc' if tool == 'long_page' else 'asc'
         select_data = 'desc' if tool == 'long_page' else 'asc'
         title = 'long_page' if tool == 'long_page' else 'short_page'
         title = 'long_page' if tool == 'long_page' else 'short_page'
 
 
-        curs.execute(db_change("select title, length(data) from data order by length(data) " + select_data + " limit 50"))
-        for data in curs.fetchall():
-            div += '<li>' + str(data[1]) + ' : <a href="/w/' + url_pas(data[0]) + '">' + html.escape(data[0]) + '</a></li>'
+        curs.execute(db_change("select title, length(data) from data order by length(data) " + select_data + " limit ?, 50"), [sql_num])
+        db_data = curs.fetchall()
+        for data in db_data:
+            div += '<li>' + str(data[1]) + ' | <a href="/w/' + url_pas(data[0]) + '">' + html.escape(data[0]) + '</a></li>'
 
 
-        div += '</ul>'
+        div += '</ul>' + next_fix('/list/document/' + ('long' if title == 'long_page' else 'short') + '/', arg_num, db_data)
 
 
         return easy_minify(flask.render_template(skin_check(),
         return easy_minify(flask.render_template(skin_check(),
             imp = [load_lang(title), wiki_set(), wiki_custom(), wiki_css([0, 0])],
             imp = [load_lang(title), wiki_set(), wiki_custom(), wiki_css([0, 0])],

+ 2 - 0
route/list_old_page.py

@@ -4,6 +4,8 @@ def list_old_page(num = 1):
     with get_db_connect() as conn:
     with get_db_connect() as conn:
         curs = conn.cursor()
         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
         
         
         curs.execute(db_change('select data from other where name = "count_all_title"'))
         curs.execute(db_change('select data from other where name = "count_all_title"'))

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

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

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

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

+ 19 - 5
route/login_login.py

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

+ 1 - 1
route/login_register_submit.py

@@ -44,7 +44,7 @@ def login_register_submit_2():
             conn.commit()
             conn.commit()
             
             
             for for_a in get_admin_list():
             for for_a in get_admin_list():
-                add_alarm(for_a, flask.session['submit_id'] + ' | <a href="/app_submit">' + load_lang('new_application') + '</a>')
+                add_alarm(for_a, flask.session['submit_id'], '<a href="/app_submit">' + load_lang('new_application') + '</a>')
 
 
             return redirect('/')
             return redirect('/')
         else:
         else:

+ 2 - 23
route/main_func_easter_egg.py

@@ -3,23 +3,6 @@ from .tool.func import *
 def main_func_easter_egg():
 def main_func_easter_egg():
     with get_db_connect() as conn:
     with get_db_connect() as conn:
         curs = conn.cursor()
         curs = conn.cursor()
-        
-        random_n = random.randrange(0, 8)
-        select_list = [
-            'PWD0ZbR7AOY', # TH06   - Shanghai Teahouse ~ Chinese Tea
-            'HoU29ljOmTE', # TH10.5 - Flawless Clothing of Celestials
-            'PR2vUm-Ald8', # TH06   - U.N. Owen Was Her
-            'opZoEmsu_Lo', # TH09   - Flowering Night
-            'txZFFTusSvw', # TH08   - Reach for the Moon ~ Immortal Smoke
-            'Ixq9xL2tvRU', # TH07   - Phantom Ensemble
-            '-3IAx_r4Au0', # TH17   - Entrusting This World to Idols ~ Idolatrize World
-            'wObZkycA6sc', # TH11   - Last Remote
-            'hZxYLa97gDg', # TH12   - Emotional Skyscraper ~ Cosmic Mind
-            'hwn2kw4eFJM', # TH07   - Border of Life
-            'wX2t_8HOtiY', # TH08   - Voyage 1969
-            'tLQjcf45fKE', # TH07   - Necrofantasia
-            # Remix by NyxTheShield
-        ]
 
 
         ip = ip_check()
         ip = ip_check()
         if ip_or_user(ip) == 0:
         if ip_or_user(ip) == 0:
@@ -27,9 +10,5 @@ def main_func_easter_egg():
             if not curs.fetchall():
             if not curs.fetchall():
                 curs.execute(db_change('insert into user_set (name, id, data) values ("get_🥚", ?, "Y")'), [ip])
                 curs.execute(db_change('insert into user_set (name, id, data) values ("get_🥚", ?, "Y")'), [ip])
                 conn.commit()
                 conn.commit()
-
-        return easy_minify(flask.render_template(skin_check(),
-            imp = ['Easter Egg', wiki_set(), wiki_custom(), wiki_css([0, 0])],
-            data = '<iframe width="640" height="360" src="https://www.youtube.com/embed/' + select_list[random_n] + '" frameborder="0" allowfullscreen></iframe>',
-            menu = [['manager', load_lang('return')]]
-        ))
+    
+        return redirect('/easter_egg_go')

+ 1 - 0
route/main_setting.py

@@ -13,6 +13,7 @@ def main_setting():
             ['sitemap', load_lang('sitemap_management')],
             ['sitemap', load_lang('sitemap_management')],
             ['top_menu', load_lang('top_menu_setting')],
             ['top_menu', load_lang('top_menu_setting')],
             ['skin_set', load_lang('main_skin_set_default')],
             ['skin_set', load_lang('main_skin_set_default')],
+            ['acl', load_lang('main_acl_setting')]
         ]
         ]
 
 
         li_data = ''.join(['<li><a href="/setting/' + str(li[0]) + '">' + li[1] + '</a></li>' for li in li_list])
         li_data = ''.join(['<li><a href="/setting/' + str(li[0]) + '">' + li[1] + '</a></li>' for li in li_list])

+ 8 - 5
route/main_setting_main.py

@@ -39,7 +39,8 @@ def main_setting_main(db_set):
             35 : ['user_name_view', ''],
             35 : ['user_name_view', ''],
             36 : ['link_case_insensitive', ''],
             36 : ['link_case_insensitive', ''],
             37 : ['move_with_redirect', ''],
             37 : ['move_with_redirect', ''],
-            38 : ['slow_thread', '']
+            38 : ['slow_thread', ''],
+            39 : ['edit_timeout', '5'],
         }
         }
 
 
         if flask.request.method == 'POST':
         if flask.request.method == 'POST':
@@ -225,9 +226,6 @@ def main_setting_main(db_set):
                         </span>
                         </span>
 
 
                         <h2>''' + load_lang('edit_set') + '''</h2>
                         <h2>''' + load_lang('edit_set') + '''</h2>
-                        <span><a href="/setting/acl">(''' + load_lang('main_acl_setting') + ''')</a></span>
-                        <hr class="main_hr">
-
                         <span>''' + load_lang('slow_edit') + ''' (''' + load_lang('second') + ''') (''' + load_lang('off') + ''' : ''' + load_lang('empty') + ''')</span>
                         <span>''' + load_lang('slow_edit') + ''' (''' + load_lang('second') + ''') (''' + load_lang('off') + ''' : ''' + load_lang('empty') + ''')</span>
                         <hr class="main_hr">
                         <hr class="main_hr">
                         <input name="slow_edit" value="''' + html.escape(d_list[19]) + '''">
                         <input name="slow_edit" value="''' + html.escape(d_list[19]) + '''">
@@ -254,7 +252,7 @@ def main_setting_main(db_set):
                         <input type="checkbox" name="history_recording_off" ''' + check_box_div[9] + '''> ''' + load_lang('set_history_recording_off') + ''' (''' + load_lang('beta') + ''')
                         <input type="checkbox" name="history_recording_off" ''' + check_box_div[9] + '''> ''' + load_lang('set_history_recording_off') + ''' (''' + load_lang('beta') + ''')
                         <hr class="main_hr">
                         <hr class="main_hr">
 
 
-                        <input type="checkbox" name="move_with_redirect" ''' + check_box_div[13] + '''> ''' + load_lang('move_with_redirect') + '''
+                        <input type="checkbox" name="move_with_redirect" ''' + check_box_div[13] + '''> ''' + load_lang('move_with_redirect') + ''' (''' + load_lang('not_working') + ''')
                         <hr class="main_hr">
                         <hr class="main_hr">
 
 
                         <span>''' + load_lang('slow_thread') + ''' (''' + load_lang('second') + ''') (''' + load_lang('off') + ''' : ''' + load_lang('empty') + ''') (''' + load_lang('not_working') + ''')</span>
                         <span>''' + load_lang('slow_thread') + ''' (''' + load_lang('second') + ''') (''' + load_lang('off') + ''' : ''' + load_lang('empty') + ''') (''' + load_lang('not_working') + ''')</span>
@@ -262,6 +260,11 @@ def main_setting_main(db_set):
                         <input name="slow_thread" value="''' + html.escape(d_list[38]) + '''">
                         <input name="slow_thread" value="''' + html.escape(d_list[38]) + '''">
                         <hr class="main_hr">
                         <hr class="main_hr">
 
 
+                        <span>''' + load_lang('edit_timeout') + ''' (''' + load_lang('second') + ''') (''' + load_lang('off') + ''' : ''' + load_lang('empty') + ''')</span>
+                        <hr class="main_hr">
+                        <input name="edit_timeout" value="''' + html.escape(d_list[39]) + '''">
+                        <hr class="main_hr">
+
                         <button id="opennamu_save_button" type="submit">''' + load_lang('save') + '''</button>
                         <button id="opennamu_save_button" type="submit">''' + load_lang('save') + '''</button>
                     </form>
                     </form>
                 '''),
                 '''),

+ 5 - 1
route/main_setting_phrase.py

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

+ 5 - 0
route/main_setting_skin_set.py

@@ -1,4 +1,5 @@
 from .tool.func import *
 from .tool.func import *
+
 from .user_setting_skin_set_main import user_setting_skin_set_main_set_list
 from .user_setting_skin_set_main import user_setting_skin_set_main_set_list
 
 
 def main_setting_skin_set():
 def main_setting_skin_set():
@@ -99,6 +100,10 @@ def main_setting_skin_set():
                         <select name="main_css_darkmode">
                         <select name="main_css_darkmode">
                             ''' + set_data["main_css_darkmode"] + '''
                             ''' + set_data["main_css_darkmode"] + '''
                         </select>
                         </select>
+                        <h3>''' + load_lang("table_scroll") + '''</h3>
+                        <select name="main_css_table_scroll">
+                            ''' + set_data["main_css_table_scroll"] + '''
+                        </select>
                         <h2>''' + load_lang("edit") + '''</h2>
                         <h2>''' + load_lang("edit") + '''</h2>
                         <h3>''' + load_lang("image_paste") + '''</h3>
                         <h3>''' + load_lang("image_paste") + '''</h3>
                         <sup>''' + load_lang('only_korean') + '''</sup> <sup>''' + load_lang('unavailable_in_monaco') + '''</sup>
                         <sup>''' + load_lang('only_korean') + '''</sup> <sup>''' + load_lang('unavailable_in_monaco') + '''</sup>

+ 3 - 0
route/main_sys_update.py

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

+ 7 - 4
route/main_tool_redirect.py

@@ -4,7 +4,7 @@ def main_tool_redirect(num = 1, add_2 = ''):
     with get_db_connect() as conn:
     with get_db_connect() as conn:
         title_list = {
         title_list = {
             0 : [load_lang('document_name'), '/acl', load_lang('acl')],
             0 : [load_lang('document_name'), '/acl', load_lang('acl')],
-            1 : [0, '/check', load_lang('check')],
+            1 : [0, '/list/user/check', load_lang('check')],
             2 : [load_lang('file_name'), '/file_filter/add', load_lang('file_filter_add')],
             2 : [load_lang('file_name'), '/file_filter/add', load_lang('file_filter_add')],
             3 : [0, '/auth/give', load_lang('authorize')],
             3 : [0, '/auth/give', load_lang('authorize')],
             4 : [0, '/record', load_lang('edit_record')],
             4 : [0, '/record', load_lang('edit_record')],
@@ -15,7 +15,7 @@ def main_tool_redirect(num = 1, add_2 = ''):
             9 : [0, '/block_log/user', load_lang('blocked_user')],
             9 : [0, '/block_log/user', load_lang('blocked_user')],
             10 : [0, '/block_log/admin', load_lang('blocked_admin')],
             10 : [0, '/block_log/admin', load_lang('blocked_admin')],
             11 : [load_lang('document_name'), '/watch_list', load_lang('add_watchlist')],
             11 : [load_lang('document_name'), '/watch_list', load_lang('add_watchlist')],
-            12 : [load_lang('compare_target'), '/check', load_lang('compare_target')],
+            12 : [load_lang('compare_target'), '/list/user/check', load_lang('compare_target')],
             13 : [load_lang('document_name'), '/edit', load_lang('load')],
             13 : [load_lang('document_name'), '/edit', load_lang('load')],
             14 : [load_lang('document_name'), '/star_doc', load_lang('add_star_doc')],
             14 : [load_lang('document_name'), '/star_doc', load_lang('add_star_doc')],
             15 : [load_lang('name_or_ip_or_regex'), '/auth/give/ban', load_lang('release')],
             15 : [load_lang('name_or_ip_or_regex'), '/auth/give/ban', load_lang('release')],
@@ -30,8 +30,11 @@ def main_tool_redirect(num = 1, add_2 = ''):
             add_1 = flask.request.form.get('name', 'test')
             add_1 = flask.request.form.get('name', 'test')
             if flask.request.method == 'POST':
             if flask.request.method == 'POST':
                 if add_2 != '':
                 if add_2 != '':
-                    flask.session['edit_load_document'] = add_1
-                    return redirect('/edit_from/' + url_pas(add_2))
+                    if num != 12:
+                        flask.session['edit_load_document'] = add_1
+                        return redirect('/edit_from/' + url_pas(add_2))
+                    else:
+                        return redirect(title_list[num][1] + '/' + url_pas(add_2) + '/normal/1/' + url_pas(add_1))
                 elif flask.request.form.get('regex', '') != '':
                 elif flask.request.form.get('regex', '') != '':
                     return redirect('/auth/give/ban_regex/' + url_pas(add_1))
                     return redirect('/auth/give/ban_regex/' + url_pas(add_1))
                 else:
                 else:

+ 1 - 1
route/recent_block.py

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

+ 1 - 2
route/recent_history_add.py

@@ -47,8 +47,7 @@ def recent_history_add(name = 'Test', do_type = ''):
 
 
                 data_preview = render_set(
                 data_preview = render_set(
                     doc_name = name, 
                     doc_name = name, 
-                    doc_data = data,
-                    data_in = ''
+                    doc_data = data
                 )
                 )
             
             
             return easy_minify(flask.render_template(skin_check(),
             return easy_minify(flask.render_template(skin_check(),

Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 468 - 481
route/tool/func.py


+ 37 - 9
route/tool/func_render.py

@@ -1,4 +1,5 @@
 from .func_tool import *
 from .func_tool import *
+
 from .func_render_namumark import class_do_render_namumark
 from .func_render_namumark import class_do_render_namumark
 
 
 # 커스텀 마크 언젠간 다시 추가 예정
 # 커스텀 마크 언젠간 다시 추가 예정
@@ -19,21 +20,24 @@ class class_do_render:
         curs = self.conn.cursor()
         curs = self.conn.cursor()
 
 
         doc_set = {}
         doc_set = {}
-        if data_in == 'from':
-            data_in = ''
+        if data_type == 'from':
             doc_set['doc_from'] = 'O'
             doc_set['doc_from'] = 'O'
+            data_type = 'view'
         
         
         data_in = (data_in + '_') if data_in != '' else ''
         data_in = (data_in + '_') if data_in != '' else ''
         doc_set['doc_include'] = data_in
         doc_set['doc_include'] = data_in
+        rep_data = ''
 
 
-        curs.execute(db_change("select set_data from data_set where doc_name = ? and set_name = 'document_markup'"), [doc_name])
-        rep_data = curs.fetchall()
-        if rep_data and rep_data[0][0] != '':
-            rep_data = rep_data[0][0]
-        else:
+        if rep_data == '' and doc_name != '':
+            curs.execute(db_change("select set_data from data_set where doc_name = ? and set_name = 'document_markup'"), [doc_name])
+            db_data = curs.fetchall()
+            if db_data and db_data[0][0] != '' and db_data[0][0] != 'normal':
+                rep_data = db_data[0][0]
+
+        if rep_data == '':
             curs.execute(db_change('select data from other where name = "markup"'))
             curs.execute(db_change('select data from other where name = "markup"'))
-            rep_data = curs.fetchall()
-            rep_data = rep_data[0][0] if rep_data else 'namumark'
+            db_data = curs.fetchall()
+            rep_data = db_data[0][0] if db_data else 'namumark'
 
 
         if rep_data == 'namumark' or rep_data == 'namumark_beta':
         if rep_data == 'namumark' or rep_data == 'namumark_beta':
             data_end = class_do_render_namumark(
             data_end = class_do_render_namumark(
@@ -56,6 +60,30 @@ class class_do_render:
                 {}
                 {}
             ]
             ]
 
 
+        if data_type == 'thread' or data_type == 'api_thread':
+            def do_thread_a_change(match):
+                data = match[2].replace('#', '')
+                data_split = data.split('-')
+                if match[1] == 'topic_a' or len(data_split) == 1:
+                    return '<a href="' + match[2] + '">' + match[2] + '</a>'
+                elif match[1] == 'topic_a_post' and len(data_split) == 3:
+                    return '<a href="/bbs/w/' + data_split[2] + '/' + data_split[1] + '#' + data_split[0] + '">#' + data_split[0] + '-' + data_split[1] + '</a>'
+                elif len(data_split) == 2:
+                    return '<a href="/thread/' + data_split[1] + '#' + data_split[0] + '">' + match[2] + '</a>'
+                else:
+                    return ''
+
+            data_end[0] = re.sub(
+                r'&lt;(topic_a(?:_post|_thread)?)&gt;((?:(?!&lt;\/topic_a(?:_post|_thread)?&gt;).)+)&lt;\/topic_a(?:_post|_thread)?&gt;',
+                do_thread_a_change,
+                data_end[0]
+            )
+            data_end[0] = re.sub(
+                r'&lt;topic_call&gt;@(?P<in>(?:(?!&lt;\/topic_call&gt;).)+)&lt;\/topic_call&gt;',
+                '<a href="/w/user:\\g<in>">@\\g<in></a>',
+                data_end[0]
+            )
+
         if data_type == 'backlink':
         if data_type == 'backlink':
             if 'backlink' in data_end[2]:
             if 'backlink' in data_end[2]:
                 backlink = data_end[2]['backlink']
                 backlink = data_end[2]['backlink']

+ 230 - 39
route/tool/func_render_namumark.py

@@ -1,7 +1,7 @@
 from .func_tool import *
 from .func_tool import *
 
 
 class class_do_render_namumark:
 class class_do_render_namumark:
-    def __init__(self, curs, doc_name, doc_data, doc_set, lang_data):
+    def __init__(self, curs, doc_name, doc_data, doc_set, lang_data, footnote = {}):
         self.curs = curs
         self.curs = curs
         
         
         self.doc_data = doc_data.replace('\r', '')
         self.doc_data = doc_data.replace('\r', '')
@@ -30,7 +30,6 @@ class class_do_render_namumark:
         except:
         except:
             self.darkmode = '0'
             self.darkmode = '0'
 
 
-
         self.data_temp_storage = {}
         self.data_temp_storage = {}
         self.data_temp_storage_count = 0
         self.data_temp_storage_count = 0
 
 
@@ -42,6 +41,7 @@ class class_do_render_namumark:
         
         
         self.data_toc = ''
         self.data_toc = ''
         self.data_footnote = {}
         self.data_footnote = {}
+        self.data_footnote_all = {}
         self.data_category = ''
         self.data_category = ''
         self.data_category_list = []
         self.data_category_list = []
 
 
@@ -152,10 +152,7 @@ class class_do_render_namumark:
 
 
         return data
         return data
 
 
-    def get_tool_footnote_make(self):
-        footnote_number_set = get_main_skin_set(self.curs, self.flask_session, 'main_css_footnote_number', self.ip)
-        footnote_number_view_set = get_main_skin_set(self.curs, self.flask_session, 'main_css_view_real_footnote_num', self.ip)
-    
+    def get_tool_footnote_make(self):    
         data = ''
         data = ''
         for for_a in self.data_footnote:
         for for_a in self.data_footnote:
             if data == '':
             if data == '':
@@ -176,6 +173,7 @@ class class_do_render_namumark:
         if data != '':
         if data != '':
             data += '</div>'
             data += '</div>'
 
 
+        self.data_footnote_all.update(self.data_footnote)
         self.data_footnote = {}
         self.data_footnote = {}
 
 
         return data
         return data
@@ -316,14 +314,14 @@ class class_do_render_namumark:
         while 1:
         while 1:
             heading_count += 1
             heading_count += 1
 
 
-            if not re.search(heading_regex, self.render_data):
+            heading_data = re.search(heading_regex, self.render_data)
+            if not heading_data:
                 break
                 break
             elif heading_count_all < 0:
             elif heading_count_all < 0:
                 print('Error : render heading count overflow')
                 print('Error : render heading count overflow')
 
 
                 break
                 break
             else:
             else:
-                heading_data = re.search(heading_regex, self.render_data)
                 heading_data_org = heading_data.group(0)
                 heading_data_org = heading_data.group(0)
                 heading_data = heading_data.groups()
                 heading_data = heading_data.groups()
 
 
@@ -635,7 +633,7 @@ class class_do_render_namumark:
                 return '<macro>' + match[0] + '(' + match[1] + ')' + '</macro>'
                 return '<macro>' + match[0] + '(' + match[1] + ')' + '</macro>'
 
 
         # double macro replace
         # double macro replace
-        self.render_data = re.sub(r'\[([^[(]+)\(([^()]+)\)\]', do_render_macro_double, self.render_data)
+        self.render_data = re.sub(r'\[([^[(\]]+)\(((?:(?!\)\]).)+)\)\]', do_render_macro_double, self.render_data)
 
 
         # single macro function
         # single macro function
         def do_render_macro_single(match):
         def do_render_macro_single(match):
@@ -709,8 +707,8 @@ class class_do_render_namumark:
 
 
             return '<' + data_name + '></' + data_name + '>'
             return '<' + data_name + '></' + data_name + '>'
 
 
-        math_regex = re.compile('\[math\(((?:(?!\[math\(|\)\]).|\n)+)\)\]', re.I)
-        math_regex_2 = re.compile('&lt;math&gt;((?:(?!&lt;math&gt;|&lt;\/math&gt;).)+)&lt;\/math&gt;', re.I)
+        math_regex = re.compile(r'\[math\(((?:(?!\[math\(|\)\]).|\n)+)\)\]', re.I)
+        math_regex_2 = re.compile(r'&lt;math&gt;((?:(?!&lt;math&gt;|&lt;\/math&gt;).)+)&lt;\/math&gt;', re.I)
 
 
         self.render_data = re.sub(math_regex_2, do_render_math_sub, self.render_data)
         self.render_data = re.sub(math_regex_2, do_render_math_sub, self.render_data)
         self.render_data = re.sub(math_regex, do_render_math_sub, self.render_data)
         self.render_data = re.sub(math_regex, do_render_math_sub, self.render_data)
@@ -720,7 +718,8 @@ class class_do_render_namumark:
         image_count = 0
         image_count = 0
         link_count_all = len(re.findall(link_regex, self.render_data)) * 4
         link_count_all = len(re.findall(link_regex, self.render_data)) * 4
         while 1:
         while 1:
-            if not re.search(link_regex, self.render_data):
+            link_data = re.search(link_regex, self.render_data)
+            if not link_data:
                 break
                 break
             elif link_count_all < 0:
             elif link_count_all < 0:
                 print('Error : render link count overflow')
                 print('Error : render link count overflow')
@@ -728,7 +727,6 @@ class class_do_render_namumark:
                 break
                 break
             else:
             else:
                 # link split
                 # link split
-                link_data = re.search(link_regex, self.render_data)
                 link_data_full = link_data.group(0)
                 link_data_full = link_data.group(0)
                 link_data = link_data.groups()
                 link_data = link_data.groups()
 
 
@@ -743,6 +741,7 @@ class class_do_render_namumark:
                     file_bgcolor = ''
                     file_bgcolor = ''
                     file_turn = ''
                     file_turn = ''
                     file_radius = ''
                     file_radius = ''
+                    file_rendering = ''
 
 
                     file_split_regex = r'(?:^|&amp;) *((?:(?!&amp;).)+)'
                     file_split_regex = r'(?:^|&amp;) *((?:(?!&amp;).)+)'
                     file_split_sub_regex = r'(^[^=]+) *= *([^=]+)'
                     file_split_sub_regex = r'(^[^=]+) *= *([^=]+)'
@@ -768,6 +767,9 @@ class class_do_render_namumark:
                                         file_turn = 'light'
                                         file_turn = 'light'
                                 elif data_sub[0] == 'border-radius':
                                 elif data_sub[0] == 'border-radius':
                                     file_radius = self.get_tool_px_add_check(data_sub[1])
                                     file_radius = self.get_tool_px_add_check(data_sub[1])
+                                elif data_sub[0] == 'rendering':
+                                    if data_sub[1] == 'pixelated':
+                                        file_rendering = 'pixelated'
 
 
                     link_main_org = ''
                     link_main_org = ''
                     link_sub = link_main
                     link_sub = link_main
@@ -828,11 +830,16 @@ class class_do_render_namumark:
                     if file_radius != '':
                     if file_radius != '':
                         file_radius = 'border-radius:' + self.get_tool_css_safe(file_radius) + ';'
                         file_radius = 'border-radius:' + self.get_tool_css_safe(file_radius) + ';'
 
 
+                    if file_rendering != '':
+                        file_rendering = 'image-rendering:' + self.get_tool_css_safe(file_rendering) + ';'
+
+                    file_style = file_width + file_height + file_align_style + file_bgcolor + file_radius + file_rendering
+
                     image_set = get_main_skin_set(self.curs, self.flask_session, 'main_css_image_set', self.ip)
                     image_set = get_main_skin_set(self.curs, self.flask_session, 'main_css_image_set', self.ip)
                     if image_set == 'new_click' or image_set == 'click':
                     if image_set == 'new_click' or image_set == 'click':
-                        file_end = '<img style="' + file_width + file_height + file_align_style + file_bgcolor + file_radius + '" id="opennamu_image_' + str(image_count) + '" alt="' + link_sub + '" src="">'
+                        file_end = '<img style="' + file_style + '" id="opennamu_image_' + str(image_count) + '" alt="' + link_sub + '" src="">'
                     else:
                     else:
-                        file_end = '<img style="' + file_width + file_height + file_align_style + file_bgcolor + file_radius + '" alt="' + link_sub + '" src="' + link_main + '">'
+                        file_end = '<img style="' + file_style + '" alt="' + link_sub + '" src="' + link_main + '">'
 
 
                     if file_align == 'center':
                     if file_align == 'center':
                         file_end = '<div style="text-align:center;">' + file_end + '</div>'
                         file_end = '<div style="text-align:center;">' + file_end + '</div>'
@@ -978,8 +985,11 @@ class class_do_render_namumark:
                     link_main = self.get_tool_data_restore(link_main, do_type = 'slash')
                     link_main = self.get_tool_data_restore(link_main, do_type = 'slash')
                     link_title = link_main
                     link_title = link_main
                     link_main = html.unescape(link_main)
                     link_main = html.unescape(link_main)
+
                     link_main = re.sub(r'"', '&quot;', link_main)
                     link_main = re.sub(r'"', '&quot;', link_main)
-                    
+                    link_main = re.sub(r'<', '&lt;', link_main)
+                    link_main = re.sub(r'>', '&gt;', link_main)
+
                     # sub not exist -> sub = main
                     # sub not exist -> sub = main
                     if link_data[1]:
                     if link_data[1]:
                         link_sub = link_data[1]
                         link_sub = link_data[1]
@@ -1114,7 +1124,7 @@ class class_do_render_namumark:
 
 
         include_num = 0
         include_num = 0
         include_set_data = get_main_skin_set(self.curs, self.flask_session, 'main_css_include_link', self.ip)
         include_set_data = get_main_skin_set(self.curs, self.flask_session, 'main_css_include_link', self.ip)
-        include_regex = re.compile('\[include\(((?:(?!\[include\(|\)\]|<\/div>).)+)\)\]', re.I)
+        include_regex = re.compile(r'\[include\(((?:(?!\[include\(|\)\]|<\/div>).)+)\)\]', re.I)
         include_count_max = len(re.findall(include_regex, self.render_data)) * 2
         include_count_max = len(re.findall(include_regex, self.render_data)) * 2
         include_change_list = {}
         include_change_list = {}
         while 1:
         while 1:
@@ -1146,9 +1156,10 @@ class class_do_render_namumark:
                             
                             
                             data_sub_name = data_sub[0]
                             data_sub_name = data_sub[0]
                             data_sub_data = self.get_tool_data_restore(data_sub[1], do_type = 'slash')
                             data_sub_data = self.get_tool_data_restore(data_sub[1], do_type = 'slash')
+                            data_sub_data = html.unescape(data_sub_data)
                             
                             
-                            data_sub_data = re.sub(r'^(?P<in>분류|category):', ':\g<in>:', data_sub_data)
-                            data_sub_data = re.sub(r'^(?P<in>파일|file):', ':\g<in>:', data_sub_data)
+                            data_sub_data = re.sub(r'^(?P<in>분류|category):', ':\\g<in>:', data_sub_data)
+                            data_sub_data = re.sub(r'^(?P<in>파일|file):', ':\\g<in>:', data_sub_data)
 
 
                             include_change_list[data_sub_name] = data_sub_data
                             include_change_list[data_sub_name] = data_sub_data
                         else:
                         else:
@@ -1202,7 +1213,7 @@ class class_do_render_namumark:
         footnote_number_set = get_main_skin_set(self.curs, self.flask_session, 'main_css_footnote_number', self.ip)
         footnote_number_set = get_main_skin_set(self.curs, self.flask_session, 'main_css_footnote_number', self.ip)
         footnote_number_view_set = get_main_skin_set(self.curs, self.flask_session, 'main_css_view_real_footnote_num', self.ip)
         footnote_number_view_set = get_main_skin_set(self.curs, self.flask_session, 'main_css_view_real_footnote_num', self.ip)
 
 
-        footnote_regex = re.compile('(?:\[\*((?:(?!\[\*|\]| ).)+)?(?: ((?:(?!\[\*|\]).)+))?\]|\[(각주|footnote)\])', re.I)
+        footnote_regex = re.compile(r'(?:\[\*((?:(?!\[\*|\]| ).)+)?(?: ((?:(?!\[\*|\]).)+))?\]|\[(각주|footnote)\])', re.I)
         footnote_count_all = len(re.findall(footnote_regex, self.render_data)) * 4
         footnote_count_all = len(re.findall(footnote_regex, self.render_data)) * 4
         while 1:
         while 1:
             footnote_num += 1
             footnote_num += 1
@@ -1236,9 +1247,15 @@ class class_do_render_namumark:
                     rfn = ''
                     rfn = ''
                     foot_v_name = ''
                     foot_v_name = ''
 
 
-                    if footnote_name in self.data_footnote:
-                        self.data_footnote[footnote_name]['list'] += [footnote_num_str]
-                        footnote_first = self.data_footnote[footnote_name]['list'][0]
+                    if footnote_name in self.data_footnote_all or footnote_name in self.data_footnote:
+                        if footnote_name in self.data_footnote:
+                            self.data_footnote[footnote_name]['list'] += [footnote_num_str]
+                            footnote_first = self.data_footnote[footnote_name]['list'][0]
+                        else:
+                            self.data_footnote[footnote_name] = {}
+                            self.data_footnote[footnote_name]['list'] = [footnote_num_str]
+                            self.data_footnote[footnote_name]['data'] = footnote_text_data
+                            footnote_first = self.data_footnote_all[footnote_name]['list'][0]
 
 
                         fn = self.doc_include + 'fn_' + footnote_first
                         fn = self.doc_include + 'fn_' + footnote_first
                         rfn = self.doc_include + 'rfn_' + footnote_num_str
                         rfn = self.doc_include + 'rfn_' + footnote_num_str
@@ -1457,7 +1474,7 @@ class class_do_render_namumark:
 
 
             return table_parameter_all
             return table_parameter_all
 
 
-        table_regex = re.compile('\n((?:(?:(?:(?:\|\|)+)|(?:\|[^|]+\|(?:\|\|)*))\n?(?:(?:(?!\|\|).)+))(?:(?:\|\||\|\|\n|(?:\|\|)+(?!\n)(?:(?:(?!\|\|).)+)\n*)*)\|\|)\n', re.DOTALL)
+        table_regex = re.compile(r'\n((?:(?:(?:(?:\|\|)+)|(?:\|[^|]+\|(?:\|\|)*))\n?(?:(?:(?!\|\|).)+))(?:(?:\|\||\|\|\n|(?:\|\|)+(?!\n)(?:(?:(?!\|\|).)+)\n*)*)\|\|)\n', re.DOTALL)
         table_sub_regex = r'(\n?)((?:\|\|)+)((?:&lt;(?:(?:(?!&lt;|&gt;).)+)&gt;)*)((?:\n*(?:(?:(?:(?!\|\|).)+)\n*)+)|(?:(?:(?!\|\|).)*))'
         table_sub_regex = r'(\n?)((?:\|\|)+)((?:&lt;(?:(?:(?!&lt;|&gt;).)+)&gt;)*)((?:\n*(?:(?:(?:(?!\|\|).)+)\n*)+)|(?:(?:(?!\|\|).)*))'
         table_caption_regex = r'^\|([^|]+)\|'
         table_caption_regex = r'^\|([^|]+)\|'
         table_count_all = len(re.findall(table_regex, self.render_data)) * 2
         table_count_all = len(re.findall(table_regex, self.render_data)) * 2
@@ -1532,7 +1549,7 @@ class class_do_render_namumark:
                 table_data_end = '<table class="' + table_parameter['class'] + '" style="' + table_parameter['table'] + '">' + table_caption + table_data_end + '</table>'
                 table_data_end = '<table class="' + table_parameter['class'] + '" style="' + table_parameter['table'] + '">' + table_caption + table_data_end + '</table>'
                 table_data_end = '<div class="table_safe" style="' + table_parameter['div'] + '">' + table_data_end + '</div>'
                 table_data_end = '<div class="table_safe" style="' + table_parameter['div'] + '">' + table_data_end + '</div>'
 
 
-                self.render_data = re.sub(table_regex, lambda x : ('\n<front_br>' + table_data_end + '<back_br>\n'), self.render_data, 1)
+                self.render_data = re.sub(table_regex, lambda x : ('\n<front_br>' + table_data_end + '\n'), self.render_data, 1)
 
 
             table_count_all -= 1
             table_count_all -= 1
     
     
@@ -1660,7 +1677,11 @@ class class_do_render_namumark:
 
 
                         if syntax_count == 0:
                         if syntax_count == 0:
                             self.render_data_js += 'hljs.highlightAll();\n'
                             self.render_data_js += 'hljs.highlightAll();\n'
-                            self.render_data_cdn += '<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.8.0/styles/default.min.css" integrity="sha512-hasIneQUHlh06VNBe7f6ZcHmeRTLIaQWFd43YriJ0UND19bvYRauxthDg8E4eVNPm9bRUhr5JGeqH7FRFXQu5g==" crossorigin="anonymous" referrerpolicy="no-referrer" />'
+                            if self.darkmode == '0':
+                                self.render_data_cdn += '<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.8.0/styles/default.min.css" integrity="sha512-hasIneQUHlh06VNBe7f6ZcHmeRTLIaQWFd43YriJ0UND19bvYRauxthDg8E4eVNPm9bRUhr5JGeqH7FRFXQu5g==" crossorigin="anonymous" referrerpolicy="no-referrer" />'
+                            else:
+                                self.render_data_cdn += '<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.8.0/styles/dark.min.css" integrity="sha512-bfLTSZK4qMP/TWeS1XJAR/VDX0Uhe84nN5YmpKk5x8lMkV0D+LwbuxaJMYTPIV13FzEv4CUOhHoc+xZBDgG9QA==" crossorigin="anonymous" referrerpolicy="no-referrer" />'
+
                             self.render_data_cdn += '<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.8.0/highlight.min.js" integrity="sha512-rdhY3cbXURo13l/WU9VlaRyaIYeJ/KBakckXIvJNAQde8DgpOmE+eZf7ha4vdqVjTtwQt69bD2wH2LXob/LB7Q==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>'
                             self.render_data_cdn += '<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.8.0/highlight.min.js" integrity="sha512-rdhY3cbXURo13l/WU9VlaRyaIYeJ/KBakckXIvJNAQde8DgpOmE+eZf7ha4vdqVjTtwQt69bD2wH2LXob/LB7Q==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>'
                             self.render_data_cdn += '<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.8.0/languages/x86asm.min.js" integrity="sha512-HeAchnWb+wLjUb2njWKqEXNTDlcd1QcyOVxb+Mc9X0bWY0U5yNHiY5hTRUt/0twG8NEZn60P3jttqBvla/i2gA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>'
                             self.render_data_cdn += '<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.8.0/languages/x86asm.min.js" integrity="sha512-HeAchnWb+wLjUb2njWKqEXNTDlcd1QcyOVxb+Mc9X0bWY0U5yNHiY5hTRUt/0twG8NEZn60P3jttqBvla/i2gA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>'
 
 
@@ -1789,7 +1810,7 @@ class class_do_render_namumark:
 
 
             middle_count_all -= 1
             middle_count_all -= 1
 
 
-        self.render_data = re.sub(r'<temp_(?P<in>(?:slash)_(?:[0-9]+))>', '<\g<in>>', self.render_data)
+        self.render_data = re.sub(r'<temp_(?P<in>(?:slash)_(?:[0-9]+))>', '<\\g<in>>', self.render_data)
 
 
     def do_render_hr(self):
     def do_render_hr(self):
         hr_regex = r'\n-{4,9}\n'
         hr_regex = r'\n-{4,9}\n'
@@ -1805,7 +1826,8 @@ class class_do_render_namumark:
 
 
             hr_count_max -= 1
             hr_count_max -= 1
 
 
-    def do_render_list(self):        
+    def do_render_list(self):
+        # 인용문
         quote_regex = r'((?:\n&gt; *[^\n]*)+)\n'
         quote_regex = r'((?:\n&gt; *[^\n]*)+)\n'
         quote_count = 0
         quote_count = 0
         quote_count_max = len(re.findall(quote_regex, self.render_data)) * 10
         quote_count_max = len(re.findall(quote_regex, self.render_data)) * 10
@@ -1819,7 +1841,7 @@ class class_do_render_namumark:
                 quote_data_org = quote_data.group(0)
                 quote_data_org = quote_data.group(0)
                 
                 
                 quote_data = quote_data.group(1)
                 quote_data = quote_data.group(1)
-                quote_data = re.sub(r'\n&gt; *(?P<in>[^\n]*)', '\g<in>\n', quote_data)
+                quote_data = re.sub(r'\n&gt; *(?P<in>[^\n]*)', '\\g<in>\n', quote_data)
                 quote_data = re.sub(r'\n$', '', quote_data)
                 quote_data = re.sub(r'\n$', '', quote_data)
                 quote_data = self.get_tool_data_revert(quote_data)
                 quote_data = self.get_tool_data_revert(quote_data)
                 quote_data = html.unescape(quote_data)
                 quote_data = html.unescape(quote_data)
@@ -1833,18 +1855,19 @@ class class_do_render_namumark:
             quote_count_max -= 1
             quote_count_max -= 1
             quote_count += 1
             quote_count += 1
 
 
+        # 일반 리스트
+        list_style = {
+            1 : 'opennamu_list_1',
+            2 : 'opennamu_list_2',
+            3 : 'opennamu_list_3',
+            4 : 'opennamu_list_4'
+        }
         def do_render_list_sub(match):
         def do_render_list_sub(match):
             list_data = match.group(2)
             list_data = match.group(2)
             list_len = len(match.group(1))
             list_len = len(match.group(1))
             if list_len == 0:
             if list_len == 0:
                 list_len = 1
                 list_len = 1
 
 
-            list_style = {
-                1 : 'opennamu_list_1',
-                2 : 'opennamu_list_2',
-                3 : 'opennamu_list_3',
-                4 : 'opennamu_list_4'
-            }
             list_style_data = 'opennamu_list_5'
             list_style_data = 'opennamu_list_5'
             if list_len in list_style:
             if list_len in list_style:
                 list_style_data = list_style[list_len]
                 list_style_data = list_style[list_len]
@@ -1869,6 +1892,173 @@ class class_do_render_namumark:
 
 
             list_count_max -= 1
             list_count_max -= 1
 
 
+        # 기타 리스트 공통 파트
+        def int_to_alpha(num):
+            alpha_list = string.ascii_lowercase
+            alpha_len = len(alpha_list)
+            end_text = ''
+
+            while num:
+                end_text = alpha_list[num % alpha_len - 1] + end_text
+                num = num // alpha_len
+
+            return end_text
+ 
+        # https://www.geeksforgeeks.org/python-program-to-convert-integer-to-roman/
+        def int_to_roman(number):
+            num = [1, 4, 5, 9, 10, 40, 50, 90, 100, 400, 500, 900, 1000]
+            sym = ["I", "IV", "V", "IX", "X", "XL", "L", "XC", "C", "CD", "D", "CM", "M"]
+            i = 12
+            end_text = ''
+
+            while number:
+                div = number // num[i]
+                number %= num[i]
+        
+                while div:
+                    end_text += sym[i]
+                    div -= 1
+
+                i -= 1
+
+            return end_text
+        
+        class do_render_list_int_to:
+            def __init__(self, do_type):
+                self.list_num = []
+                self.do_type = do_type
+
+            def __call__(self, match):
+                list_data = match.group(3)
+                list_start = match.group(2)
+                list_len = len(match.group(1))
+                if list_len == 0:
+                    list_len = 1
+
+                if len(self.list_num) >= list_len:
+                    self.list_num[list_len - 1] += 1
+
+                    for for_a in range(list_len, len(self.list_num)):
+                        self.list_num[for_a] = 0
+                else:
+                    self.list_num += [1] * (list_len - len(self.list_num))
+
+                if list_start:
+                    self.list_num[list_len - 1] = int(list_start)
+
+                if self.do_type == 'int':
+                    change_text = str(self.list_num[list_len - 1])
+                elif self.do_type == 'roman_big':
+                    change_text = int_to_roman(self.list_num[list_len - 1])
+                elif self.do_type == 'roman_small':
+                    change_text = int_to_roman(self.list_num[list_len - 1]).lower()
+                elif self.do_type == 'alpha_big':
+                    change_text = int_to_alpha(self.list_num[list_len - 1])
+                else:
+                    change_text = int_to_alpha(self.list_num[list_len - 1]).upper()
+
+                return '<li style="margin-left: ' + str((list_len - 1) * 20) + 'px;" class="opennamu_list_none">' + change_text + '. ' + list_data + '</li>'
+
+        # 숫자 리스트
+        list_regex = r'((?:\n *1\. ?[^\n]*)+)\n'
+        list_count_max = len(re.findall(list_regex, self.render_data)) * 3
+        while 1:
+            list_data = re.search(list_regex, self.render_data)
+            if list_count_max < 0:
+                break
+            elif not list_data:
+                break
+            else:
+                list_data = list_data.group(1)
+                list_sub_regex = r'\n( *)1\.(?:#([0-9]*))? ?([^\n]*)'
+
+                list_class = do_render_list_int_to('int')
+                list_data = re.sub(list_sub_regex, list_class, list_data)
+
+                self.render_data = re.sub(list_regex, lambda x : ('\n<front_br><ul class="opennamu_ul">' + list_data + '</ul><back_br>\n'), self.render_data, 1)
+
+            list_count_max -= 1
+
+        # 소문자 리스트
+        list_regex = r'((?:\n *a\. ?[^\n]*)+)\n'
+        list_count_max = len(re.findall(list_regex, self.render_data)) * 3
+        while 1:
+            list_data = re.search(list_regex, self.render_data)
+            if list_count_max < 0:
+                break
+            elif not list_data:
+                break
+            else:
+                list_data = list_data.group(1)
+                list_sub_regex = r'\n( *)a.(?:#([0-9]*))? ?([^\n]*)'
+
+                list_class = do_render_list_int_to('alpha_small')
+                list_data = re.sub(list_sub_regex, list_class, list_data)
+
+                self.render_data = re.sub(list_regex, lambda x : ('\n<front_br><ul class="opennamu_ul">' + list_data + '</ul><back_br>\n'), self.render_data, 1)
+
+            list_count_max -= 1
+
+        # 대문자 리스트
+        list_regex = r'((?:\n *A\. ?[^\n]*)+)\n'
+        list_count_max = len(re.findall(list_regex, self.render_data)) * 3
+        while 1:
+            list_data = re.search(list_regex, self.render_data)
+            if list_count_max < 0:
+                break
+            elif not list_data:
+                break
+            else:
+                list_data = list_data.group(1)
+                list_sub_regex = r'\n( *)A.(?:#([0-9]*))? ?([^\n]*)'
+
+                list_class = do_render_list_int_to('alpha_big')
+                list_data = re.sub(list_sub_regex, list_class, list_data)
+
+                self.render_data = re.sub(list_regex, lambda x : ('\n<front_br><ul class="opennamu_ul">' + list_data + '</ul><back_br>\n'), self.render_data, 1)
+
+            list_count_max -= 1
+
+        # 로마자 대문자 리스트
+        list_regex = r'((?:\n *I\. ?[^\n]*)+)\n'
+        list_count_max = len(re.findall(list_regex, self.render_data)) * 3
+        while 1:
+            list_data = re.search(list_regex, self.render_data)
+            if list_count_max < 0:
+                break
+            elif not list_data:
+                break
+            else:
+                list_data = list_data.group(1)
+                list_sub_regex = r'\n( *)I.(?:#([0-9]*))? ?([^\n]*)'
+
+                list_class = do_render_list_int_to('roman_big')
+                list_data = re.sub(list_sub_regex, list_class, list_data)
+
+                self.render_data = re.sub(list_regex, lambda x : ('\n<front_br><ul class="opennamu_ul">' + list_data + '</ul><back_br>\n'), self.render_data, 1)
+
+            list_count_max -= 1
+
+        # 로마자 소문자 리스트
+        list_regex = r'((?:\n *i\. ?[^\n]*)+)\n'
+        list_count_max = len(re.findall(list_regex, self.render_data)) * 3
+        while 1:
+            list_data = re.search(list_regex, self.render_data)
+            if list_count_max < 0:
+                break
+            elif not list_data:
+                break
+            else:
+                list_data = list_data.group(1)
+                list_sub_regex = r'\n( *)i.(?:#([0-9]*))? ?([^\n]*)'
+
+                list_class = do_render_list_int_to('roman_small')
+                list_data = re.sub(list_sub_regex, list_class, list_data)
+
+                self.render_data = re.sub(list_regex, lambda x : ('\n<front_br><ul class="opennamu_ul">' + list_data + '</ul><back_br>\n'), self.render_data, 1)
+
+            list_count_max -= 1
+
     def do_render_remark(self):
     def do_render_remark(self):
         self.render_data = re.sub(r'\n##[^\n]+', '\n<front_br>', self.render_data)
         self.render_data = re.sub(r'\n##[^\n]+', '\n<front_br>', self.render_data)
 
 
@@ -1973,7 +2163,7 @@ class class_do_render_namumark:
                 toc_data_on == 1:
                 toc_data_on == 1:
                 self.render_data = re.sub(r'<toc_no_auto>', '', self.render_data)
                 self.render_data = re.sub(r'<toc_no_auto>', '', self.render_data)
             else:
             else:
-                self.render_data = re.sub(r'(?P<in><h[1-6] id="[^"]*">)', '<br>' + self.data_toc + '\g<in>', self.render_data, 1)
+                self.render_data = re.sub(r'(?P<in><h[1-6] id="[^"]*">)', '<br>' + self.data_toc + '\\g<in>', self.render_data, 1)
         else:
         else:
             self.render_data = re.sub(r'<toc_need_part>', '', self.render_data)
             self.render_data = re.sub(r'<toc_need_part>', '', self.render_data)
             self.render_data = re.sub(r'<toc_no_auto>', '', self.render_data)
             self.render_data = re.sub(r'<toc_no_auto>', '', self.render_data)
@@ -1981,7 +2171,7 @@ class class_do_render_namumark:
         def do_render_last_footnote(match):
         def do_render_last_footnote(match):
             match = match.group(1)
             match = match.group(1)
 
 
-            find_regex = re.compile('<footnote_title id="' + match + '_title">((?:(?!<footnote_title|<\/footnote_title>).)*)<\/footnote_title>')
+            find_regex = re.compile(r'<footnote_title id="' + match + r'_title">((?:(?!<footnote_title|<\/footnote_title>).)*)<\/footnote_title>')
             find_data = re.search(find_regex, self.render_data)
             find_data = re.search(find_regex, self.render_data)
             if find_data:
             if find_data:
                 find_data = find_data.group(1)
                 find_data = find_data.group(1)
@@ -2008,10 +2198,10 @@ class class_do_render_namumark:
             self.do_render_list()
             self.do_render_list()
             self.do_render_macro()
             self.do_render_macro()
             self.do_render_link()
             self.do_render_link()
-            self.do_redner_footnote()
             self.do_render_text()
             self.do_render_text()
             self.do_render_hr()
             self.do_render_hr()
             self.do_render_heading()
             self.do_render_heading()
+            self.do_redner_footnote()
             
             
         self.do_render_last()
         self.do_render_last()
 
 
@@ -2020,6 +2210,7 @@ class class_do_render_namumark:
             self.render_data_js, # js
             self.render_data_js, # js
             {
             {
                 'backlink' : self.data_backlink, # backlink
                 'backlink' : self.data_backlink, # backlink
-                'include' : list(reversed(self.data_include)) # include data
+                'include' : list(reversed(self.data_include)), # include data
+                'footnote' : self.data_footnote_all # footnote
             } # other
             } # other
         ]
         ]

+ 1 - 0
route/tool/func_tool.py

@@ -2,6 +2,7 @@ import urllib.parse
 import datetime
 import datetime
 import hashlib
 import hashlib
 import flask
 import flask
+import string
 import re
 import re
 
 
 import os
 import os

+ 21 - 57
route/topic.py

@@ -1,5 +1,8 @@
 from .tool.func import *
 from .tool.func import *
-from .api_topic import api_topic
+
+from .api_topic import api_topic, api_topic_thread_pre_render
+
+from .edit import edit_editor
 
 
 def topic(topic_num = 0, do_type = '', doc_name = 'Test'):
 def topic(topic_num = 0, do_type = '', doc_name = 'Test'):
     with get_db_connect() as conn:
     with get_db_connect() as conn:
@@ -11,7 +14,12 @@ def topic(topic_num = 0, do_type = '', doc_name = 'Test'):
         if topic_view_acl == 1:
         if topic_view_acl == 1:
             return re_error('/ban')
             return re_error('/ban')
 
 
+        ip = ip_check()
+
         if flask.request.method == 'POST' and do_type == '':
         if flask.request.method == 'POST' and do_type == '':
+            if do_edit_slow_check('thread') == 1:
+                return re_error('/error/42')
+
             name = flask.request.form.get('topic', 'Test')
             name = flask.request.form.get('topic', 'Test')
             sub = flask.request.form.get('title', 'Test')
             sub = flask.request.form.get('title', 'Test')
             
             
@@ -34,7 +42,6 @@ def topic(topic_num = 0, do_type = '', doc_name = 'Test'):
             else:
             else:
                 captcha_post('', 0)
                 captcha_post('', 0)
 
 
-            ip = ip_check()
             today = get_time()
             today = get_time()
 
 
             if topic_acl == 1:
             if topic_acl == 1:
@@ -65,54 +72,15 @@ def topic(topic_num = 0, do_type = '', doc_name = 'Test'):
                         y_check = 1
                         y_check = 1
 
 
                 if y_check == 1:
                 if y_check == 1:
-                    add_alarm(match, ip + ' | <a href="/thread/' + topic_num + '#' + num + '">' + html.escape(name) + ' | ' + html.escape(sub) + ' | #' + num + '</a>')
-
-            cate_re = re.compile(r'\[\[((?:분류|category):(?:(?:(?!\]\]).)*))\]\]', re.I)
-            data = cate_re.sub('[br]', flask.request.form.get('content', 'Test').replace('\r', ''))
-
-            call_thread_regex = r"( |\n|^)(?:#([0-9]+))( |\n|$)"
-            call_thread_count = len(re.findall(call_thread_regex, data)) * 3
-            while 1:
-                rd_data = re.search(call_thread_regex, data)
-                if call_thread_count < 0:
-                    break
-                elif not rd_data:
-                    break
-                else:
-                    rd_data = rd_data.groups()
-
-                    curs.execute(db_change("select ip from topic where code = ? and id = ?"), [topic_num, rd_data[1]])
-                    ip_data = curs.fetchall()
-                    if ip_data and ip_or_user(ip_data[0][0]) == 0 and ip != ip_data[0][0]:
-                        add_alarm(ip_data[0][0], ip + ' | <a href="/thread/' + topic_num + '#' + num + '">' + html.escape(name) + ' | ' + html.escape(sub) + ' | #' + num + '</a>')
-
-                    data = re.sub(call_thread_regex, rd_data[0] + '<topic_a>#' + rd_data[1] + '</topic_a>' + rd_data[2], data, 1)
-
-                call_thread_count -= 1
-
-            call_user_regex = r"( |\n|^)(?:@([^ ]+))( |\n|$)"
-            call_user_count = len(re.findall(call_user_regex, data)) * 3
-            while 1:
-                rd_data = re.search(call_user_regex, data)
-                if call_user_count < 0:
-                    break
-                elif not rd_data:
-                    break
-                else:
-                    rd_data = rd_data.groups()
-
-                    curs.execute(db_change("select ip from history where ip = ? limit 1"), [rd_data[1]])
-                    ip_data = curs.fetchall()
-                    if not ip_data:
-                        curs.execute(db_change("select ip from topic where ip = ? limit 1"), [rd_data[1]])
-                        ip_data = curs.fetchall()
-
-                    if ip_data and ip_or_user(ip_data[0][0]) == 0 and ip != ip_data[0][0]:
-                        add_alarm(ip_data[0][0], ip + ' | <a href="/thread/' + topic_num + '#' + num + '">' + html.escape(name) + ' | ' + html.escape(sub) + ' | #' + num + '</a>')
-
-                    data = re.sub(call_user_regex, rd_data[0] + '<topic_call>@' + rd_data[1] + '</topic_call>' + rd_data[2], data, 1)
+                    add_alarm(match, ip, '<a href="/thread/' + topic_num + '#' + num + '">' + html.escape(name) + ' - ' + html.escape(sub) + '#' + num + '</a>')
+            
+            curs.execute(db_change("select ip from topic where code = ? and id = '1'"), [topic_num])
+            ip_data = curs.fetchall()
+            if ip_data and ip_or_user(ip_data[0][0]) == 0:
+                add_alarm(ip_data[0][0], ip, '<a href="/thread/' + topic_num + '#' + num + '">' + html.escape(name) + ' - ' + html.escape(sub) + '#' + num + '</a>')
 
 
-                call_user_count -= 1
+            data = flask.request.form.get('content', 'Test').replace('\r', '')
+            data = api_topic_thread_pre_render(curs, data, num, ip, topic_num, name, sub)
 
 
             do_add_thread(
             do_add_thread(
                 topic_num,
                 topic_num,
@@ -161,9 +129,7 @@ def topic(topic_num = 0, do_type = '', doc_name = 'Test'):
                 thread_data = thread_data.replace('\r', '')
                 thread_data = thread_data.replace('\r', '')
 
 
                 thread_data_preview = render_set(
                 thread_data_preview = render_set(
-                    doc_name = '', 
-                    doc_data = thread_data,
-                    data_in = ''
+                    doc_data = thread_data
                 )
                 )
 
 
             acl_display = 'display: none;' if topic_acl == 1 else ''
             acl_display = 'display: none;' if topic_acl == 1 else ''
@@ -212,15 +178,13 @@ def topic(topic_num = 0, do_type = '', doc_name = 'Test'):
                             <hr class="main_hr">
                             <hr class="main_hr">
                         </div>
                         </div>
                         
                         
-                        <div>''' + edit_button('opennamu_edit_textarea') + '''</div>
-
-                        <textarea id="opennamu_edit_textarea" class="opennamu_textarea_100" placeholder="''' + topic_text + '''" name="content">''' + html.escape(thread_data) + '''</textarea>
+                        ''' + edit_editor(curs, ip, thread_data, 'thread') + '''
                         <hr class="main_hr">
                         <hr class="main_hr">
                         
                         
                         ''' + captcha_get() + ip_warning() + '''
                         ''' + captcha_get() + ip_warning() + '''
                         
                         
-                        <button id="opennamu_save_button" formaction="/thread/''' + topic_num + '''" type="submit">''' + load_lang('send') + '''</button>
-                        <button id="opennamu_preview_button" formaction="/thread_preview/''' + topic_num + '''#opennamu_edit_textarea" type="submit">''' + load_lang('preview') + '''</button>
+                        <button id="opennamu_save_button" formaction="/thread/''' + topic_num + '''" type="submit" onclick="do_monaco_to_textarea(); do_stop_exit_release();">''' + load_lang('send') + '''</button>
+                        <button id="opennamu_preview_button" formaction="/thread_preview/''' + topic_num + '''#opennamu_edit_textarea" type="submit" onclick="do_monaco_to_textarea(); do_stop_exit_release();">''' + load_lang('preview') + '''</button>
                     </form>
                     </form>
                     <hr class="main_hr">
                     <hr class="main_hr">
                     
                     

+ 1 - 0
route/topic_list.py

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

+ 1 - 1
route/user_info.py

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

+ 1 - 3
route/user_setting.py

@@ -7,8 +7,6 @@ def user_setting():
         support_language = ['default'] + get_init_set_list()['language']['list']
         support_language = ['default'] + get_init_set_list()['language']['list']
         
         
         ip = ip_check()
         ip = ip_check()
-        if ban_check(ip) == 1:
-            return re_error('/ban')
 
 
         if ip_or_user(ip) == 0:
         if ip_or_user(ip) == 0:
             if flask.request.method == 'POST':
             if flask.request.method == 'POST':
@@ -188,4 +186,4 @@ def user_setting():
                         </form>
                         </form>
                     ''',
                     ''',
                     menu = [['user', load_lang('return')]]
                     menu = [['user', load_lang('return')]]
-                ))
+                ))

+ 9 - 0
route/user_setting_skin_set_main.py

@@ -64,6 +64,10 @@ def user_setting_skin_set_main_set_list():
             ['default', load_lang('default')],
             ['default', load_lang('default')],
             ['off', load_lang('off')],
             ['off', load_lang('off')],
             ['on', load_lang('use')]
             ['on', load_lang('use')]
+        ], 'main_css_table_scroll' : [
+            ['default', load_lang('default')],
+            ['off', load_lang('off')],
+            ['on', load_lang('use')]
         ]
         ]
     }
     }
 
 
@@ -198,6 +202,11 @@ def user_setting_skin_set_main():
                         <select name="main_css_darkmode">
                         <select name="main_css_darkmode">
                             ''' + set_data["main_css_darkmode"] + '''
                             ''' + set_data["main_css_darkmode"] + '''
                         </select>
                         </select>
+                        <h3>''' + load_lang("table_scroll") + '''</h3>
+                        ''' + set_data_main["main_css_table_scroll"] + '''
+                        <select name="main_css_table_scroll">
+                            ''' + set_data["main_css_table_scroll"] + '''
+                        </select>
                         <h2>''' + load_lang("edit") + '''</h2>
                         <h2>''' + load_lang("edit") + '''</h2>
                         <h3>''' + load_lang("image_paste") + '''</h3>
                         <h3>''' + load_lang("image_paste") + '''</h3>
                         <sup>''' + load_lang('only_korean') + '''</sup> <sup>''' + load_lang('unavailable_in_monaco') + '''</sup>
                         <sup>''' + load_lang('only_korean') + '''</sup> <sup>''' + load_lang('unavailable_in_monaco') + '''</sup>

+ 4 - 5
route/view_acl.py

@@ -83,7 +83,7 @@ def view_acl(name):
                         data_type = 'backlink'
                         data_type = 'backlink'
                     )
                     )
 
 
-            markup_data = markup_data if markup_data != '' else 'default'
+            markup_data = markup_data if markup_data != '' else 'normal'
 
 
             if user_page == 1:
             if user_page == 1:
                 admin_check(5, check_data + ' (' + all_d + ')' + ' (' + markup_data + ')')
                 admin_check(5, check_data + ' (' + all_d + ')' + ' (' + markup_data + ')')
@@ -155,18 +155,17 @@ def view_acl(name):
                 <h2>''' + load_lang('markup') + '''</h2>
                 <h2>''' + load_lang('markup') + '''</h2>
             '''
             '''
 
 
-
             curs.execute(db_change("select set_data from data_set where doc_name = ? and set_name = 'document_markup'"), [name])
             curs.execute(db_change("select set_data from data_set where doc_name = ? and set_name = 'document_markup'"), [name])
             db_data = curs.fetchall()
             db_data = curs.fetchall()
             markup_load = db_data[0][0] if db_data and db_data[0][0] != '' else ''
             markup_load = db_data[0][0] if db_data and db_data[0][0] != '' else ''
 
 
-            markup_list = ['default'] + get_init_set_list('markup')['list']
+            markup_list = ['normal'] + get_init_set_list('markup')['list']
             markup_html = ''
             markup_html = ''
             for for_a in markup_list:
             for for_a in markup_list:
                 if markup_load == for_a:
                 if markup_load == for_a:
-                    markup_html = '<option value="' + (for_a if for_a != 'default' else '') + '">' + for_a + '</option>' + markup_html
+                    markup_html = '<option value="' + (for_a if for_a != 'normal' else '') + '">' + for_a + '</option>' + markup_html
                 else:
                 else:
-                    markup_html += '<option value="' + (for_a if for_a != 'default' else '') + '">' + for_a + '</option>'
+                    markup_html += '<option value="' + (for_a if for_a != 'normal' else '') + '">' + for_a + '</option>'
             
             
             markup_html = '<select name="document_markup" ' + check_ok + '>' + markup_html + '</select>'
             markup_html = '<select name="document_markup" ' + check_ok + '>' + markup_html + '</select>'
 
 

+ 4 - 4
route/view_diff.py

@@ -60,7 +60,7 @@ def view_diff(name = 'Test', num_a = 1, num_b = 1):
 
 
                         temp_list += [[line, for_a[0], for_a[1]]]
                         temp_list += [[line, for_a[0], for_a[1]]]
 
 
-                result = '<table style="width: 100%;"><tr><td colspan="2">r' + first + ' ➤ r' + second + '</td></tr>'
+                result = '<table style="width: 100%; white-space: pre-wrap;"><tr><td colspan="2">r' + first + ' ➤ r' + second + '</td></tr>'
                 result += '<tr><td style="width: 40px; user-select: none;">'
                 result += '<tr><td style="width: 40px; user-select: none;">'
 
 
                 # 개행만 추가된 경우 조정 필요
                 # 개행만 추가된 경우 조정 필요
@@ -76,11 +76,11 @@ def view_diff(name = 'Test', num_a = 1, num_b = 1):
                             result += '</td></tr><tr><td style="width: 40px; user-select: none;">' + str(line) + '</td><td>'
                             result += '</td></tr><tr><td style="width: 40px; user-select: none;">' + str(line) + '</td><td>'
 
 
                     if for_a[1] == 1:
                     if for_a[1] == 1:
-                        result += '<span style="background: #eaf2c2;">' + for_a[2] + '</span>'
+                        result += '<span style="background: #eaf2c2;">' + html.escape(for_a[2]) + '</span>'
                     elif for_a[1] == 0:
                     elif for_a[1] == 0:
-                        result += for_a[2]
+                        result += html.escape(for_a[2])
                     else:
                     else:
-                        result += '<span style="background: #fadad7;">' + for_a[2] + '</span>'
+                        result += '<span style="background: #fadad7;">' + html.escape(for_a[2]) + '</span>'
 
 
                 result += '</td></tr></table>'
                 result += '</td></tr></table>'
 
 

+ 1 - 1
route/view_read.py

@@ -144,7 +144,7 @@ def view_read(name = 'Test', doc_rev = '', doc_from = '', do_type = ''):
         end_data = render_set(
         end_data = render_set(
             doc_name = name,
             doc_name = name,
             doc_data = data[0][0] if data else None,
             doc_data = data[0][0] if data else None,
-            data_in = 'from' if do_type == 'from' else ''
+            data_type = 'from' if do_type == 'from' else 'view'
         )
         )
 
 
         if end_data == 'HTTP Request 401.3':
         if end_data == 'HTTP Request 401.3':

+ 1 - 1
route/vote_add.py

@@ -64,7 +64,7 @@ def vote_add():
                         '<hr class="main_hr">' + \
                         '<hr class="main_hr">' + \
                         '<input type="checkbox" value="Y" name="open_select"> ' + load_lang('open_vote') + \
                         '<input type="checkbox" value="Y" name="open_select"> ' + load_lang('open_vote') + \
                         '<h2>' + load_lang('period') + '</h2>'
                         '<h2>' + load_lang('period') + '</h2>'
-                        '<input type="date" name="date" pattern="\d{4}-\d{2}-\d{2}">' + \
+                        '<input type="date" name="date" pattern="\\d{4}-\\d{2}-\\d{2}">' + \
                         '<hr class="main_hr">' + \
                         '<hr class="main_hr">' + \
                         '<input type="checkbox" value="Y" name="limitless"> ' + load_lang('limitless') + \
                         '<input type="checkbox" value="Y" name="limitless"> ' + load_lang('limitless') + \
                         '<h2>' + load_lang('acl') + '</h2>' + \
                         '<h2>' + load_lang('acl') + '</h2>' + \

+ 2 - 2
route/vote_select.py

@@ -1,10 +1,10 @@
 from .tool.func import *
 from .tool.func import *
 
 
 def vote_select(num = 1):
 def vote_select(num = 1):
-    num = str(num)
-    
     with get_db_connect() as conn:
     with get_db_connect() as conn:
         curs = conn.cursor()
         curs = conn.cursor()
+        
+        num = str(num)
 
 
         curs.execute(db_change('select name, subject, data, type from vote where id = ? and user = ""'), [num])
         curs.execute(db_change('select name, subject, data, type from vote where id = ? and user = ""'), [num])
         data_list = curs.fetchall()
         data_list = curs.fetchall()

binární
route_go/bin/main_easter_egg.amd64.bin


binární
route_go/bin/main_easter_egg.amd64.exe


binární
route_go/bin/main_easter_egg.arm64.bin


binární
route_go/bin/main_easter_egg.arm64.exe


+ 22 - 0
route_go/linux_amd64.sh

@@ -0,0 +1,22 @@
+echo "file_name : "
+read file_name
+
+export GOOS=linux
+export GOARCH=amd64
+go build $file_name.go
+mv $file_name ./bin/$file_name.amd64.bin
+
+export GOOS=linux
+export GOARCH=arm64
+go build $file_name.go
+mv $file_name ./bin/$file_name.arm64.bin
+
+export GOOS=windows
+export GOARCH=amd64
+go build $file_name.go
+mv $file_name.exe ./bin/$file_name.amd64.exe
+
+export GOOS=windows
+export GOARCH=arm64
+go build $file_name.go
+mv $file_name.exe ./bin/$file_name.arm64.exe

+ 37 - 0
route_go/main_easter_egg.go

@@ -0,0 +1,37 @@
+package main
+
+import (
+	"fmt"
+	"math/rand"
+	"time"
+)
+
+func main() {
+	rand.Seed(time.Now().UnixNano())
+
+	select_list := []string{
+		"PWD0ZbR7AOY", // Shanghai Teahouse ~ Chinese Tea
+		"HoU29ljOmTE", // Flawless Clothing of Celestials
+		"PR2vUm-Ald8", // U.N. Owen Was Her
+		"opZoEmsu_Lo", // Night of Nights
+		"txZFFTusSvw", // Reach for the Moon ~ Immortal Smoke
+		"Ixq9xL2tvRU", // Phantom Ensemble
+		"-3IAx_r4Au0", // Entrusting This World to Idols ~ Idolatrize World
+		"wObZkycA6sc", // Last Remote
+		"hZxYLa97gDg", // Emotional Skyscraper ~ Cosmic Mind
+		"hwn2kw4eFJM", // Border of Life
+		"wX2t_8HOtiY", // Voyage 1969
+		"tLQjcf45fKE", // Necrofantasia
+		"7DvMRAMuMrU", // Where Is That Bustling Marketplace Now ~ Immemorial Marketeers
+		// Remix by NyxTheShield
+		"SXFP9HgWBYQ", // 세계는 귀엽게 만들어져 있다
+		"YDrgO0Oj3Fg", // 죽취비상
+		"wxWV_sUGPB0", // 디자이어 드라이브
+		"uw0h2O7UaZ8", // 100번째 블랙 마켓
+		"blE4lnfEWbU", // 일렉트릭 헤리티지
+		// Remix by KR. Palto47
+	}
+	select_str := select_list[rand.Intn(len(select_list)-1)]
+
+	fmt.Println("<iframe width=\"640\" height=\"360\" src=\"https://www.youtube.com/embed/" + select_str + "\" frameborder=\"0\" allowfullscreen></iframe>")
+}

+ 1 - 1
version.json

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

+ 4 - 0
views/main_css/css/main.css

@@ -377,4 +377,8 @@ s:hover, strike:hover, del:hover {
     content: "⬥";
     content: "⬥";
     width: 1.2em;
     width: 1.2em;
     margin-left: -1.2em;
     margin-left: -1.2em;
+}
+
+.opennamu_list_none {
+    list-style: none;
 }
 }

+ 5 - 5
views/main_css/css/sub/dark.css

@@ -45,7 +45,7 @@ input::placeholder, textarea::placeholder, select::placeholder {
 }
 }
 
 
 pre#syntax, pre#syntax code {
 pre#syntax, pre#syntax code {
-    background: black;
+    background: #313236;
 }
 }
 
 
 .hljs, .hljs-subst {
 .hljs, .hljs-subst {
@@ -53,15 +53,15 @@ pre#syntax, pre#syntax code {
 }
 }
 
 
 blockquote {
 blockquote {
-    background-color: black;
-    border-left: 5px solid #eee;
+    background-color: #313236;
+    border-left: 4px solid #eee;
 }
 }
 
 
 .opennamu_spead_footnote {
 .opennamu_spead_footnote {
-    background-color: black;
+    background-color: #313236;
     color: white;
     color: white;
 }
 }
 
 
 .opennamu_popup_footnote {
 .opennamu_popup_footnote {
-    background-color: black;
+    background-color: #313236;
 }
 }

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

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

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

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

+ 15 - 0
views/main_css/js/route/bbs_w_post.js

@@ -0,0 +1,15 @@
+function opennamu_change_comment(get_id) {
+    var _a;
+    var input = document.querySelector('#opennamu_comment_select');
+    if (input != null) {
+        input.value = get_id;
+        (_a = document.getElementById('opennamu_edit_textarea')) === null || _a === void 0 ? void 0 : _a.focus();
+    }
+}
+function opennamu_return_comment() {
+    var _a;
+    var input = document.querySelector('#opennamu_comment_select');
+    if (input != null) {
+        (_a = document.getElementById(input.value)) === null || _a === void 0 ? void 0 : _a.focus();
+    }
+}

+ 14 - 0
views/main_css/js/route/bbs_w_post.ts

@@ -0,0 +1,14 @@
+function opennamu_change_comment(get_id : string): void {
+    const input = document.querySelector('#opennamu_comment_select') as HTMLInputElement | null;
+    if(input != null) {
+        input.value = get_id;
+        document.getElementById('opennamu_edit_textarea')?.focus();
+    }
+}
+
+function opennamu_return_comment(): void {
+    const input = document.querySelector('#opennamu_comment_select') as HTMLInputElement | null;
+    if(input != null) {
+        document.getElementById(input.value)?.focus();
+    }
+}

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

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

+ 8 - 0
views/ringo/css/main.css

@@ -337,6 +337,10 @@ input, textarea, button, select {
     background-color: white;
     background-color: white;
 }
 }
 
 
+input, textarea {
+    width: calc(100% - 20px);
+}
+
 #main_data button:hover {
 #main_data button:hover {
     background-color: #eee;
     background-color: #eee;
 
 
@@ -393,4 +397,8 @@ input, textarea, button, select {
 
 
 #nav_bar a {
 #nav_bar a {
     color: black;
     color: black;
+}
+
+pre#syntax, pre#syntax code {
+    border: 0;
 }
 }

+ 1 - 1
views/ringo/index.html

@@ -13,7 +13,7 @@
         <script src="/views/ringo/js/main.js?ver=2"></script>
         <script src="/views/ringo/js/main.js?ver=2"></script>
         <script src="/views/ringo/js/sidebar.js?ver=1"></script>
         <script src="/views/ringo/js/sidebar.js?ver=1"></script>
         <script src="/views/ringo/js/skin_set.js?ver=1"></script>
         <script src="/views/ringo/js/skin_set.js?ver=1"></script>
-        <link rel="stylesheet" href="/views/ringo/css/main.css?ver=2">
+        <link rel="stylesheet" href="/views/ringo/css/main.css?ver=3">
         {% if request.cookies.get('main_css_darkmode', '') == '1' %}
         {% if request.cookies.get('main_css_darkmode', '') == '1' %}
             <link rel="stylesheet" href="/views/main_css/css/sub/dark.css?ver=1">
             <link rel="stylesheet" href="/views/main_css/css/sub/dark.css?ver=1">
             <link rel="stylesheet" href="/views/ringo/css/dark.css?ver=1">
             <link rel="stylesheet" href="/views/ringo/css/dark.css?ver=1">

+ 4 - 0
views/tenshi/css/main.css

@@ -331,6 +331,10 @@ textarea, input, pre {
     box-shadow: 0 2px 4px 0 rgba(0,0,0,0.16), 0 2px 10px 0 rgba(0,0,0,0.12);
     box-shadow: 0 2px 4px 0 rgba(0,0,0,0.16), 0 2px 10px 0 rgba(0,0,0,0.12);
 }
 }
 
 
+textarea, input {
+    width: calc(100% - 10px);
+}
+
 pre {
 pre {
     padding: 10px;
     padding: 10px;
 }
 }

+ 1 - 1
views/tenshi/index.html

@@ -8,7 +8,7 @@
             <title>{{imp[0]}} - {{imp[1][0]}}</title>
             <title>{{imp[0]}} - {{imp[1][0]}}</title>
         {% endif %}
         {% endif %}
         {{imp[3][3]|safe}}
         {{imp[3][3]|safe}}
-        <link rel="stylesheet" href="/views/tenshi/css/main.css?ver=21">
+        <link rel="stylesheet" href="/views/tenshi/css/main.css?ver=22">
         {% if request.cookies.get('main_css_darkmode', '') == '1' %}
         {% if request.cookies.get('main_css_darkmode', '') == '1' %}
             <link rel="stylesheet" href="/views/main_css/css/sub/dark.css?ver=1">
             <link rel="stylesheet" href="/views/main_css/css/sub/dark.css?ver=1">
             <link rel="stylesheet" href="/views/tenshi/css/dark.css?ver=9">
             <link rel="stylesheet" href="/views/tenshi/css/dark.css?ver=9">

+ 1 - 1
views/tenshi/info.json

@@ -1,5 +1,5 @@
 {
 {
     "name" : "Tenshi",
     "name" : "Tenshi",
-    "skin_ver" : "v2.0.5",
+    "skin_ver" : "v2.0.6",
     "require_ver" : "3500110"
     "require_ver" : "3500110"
 }
 }

Některé soubory nejsou zobrazeny, neboť je v těchto rozdílových datech změněno mnoho souborů