Browse Source

Merge pull request #2096 from openNAMU/dev

Golang으로 많은 파트 이전
잉여개발기 2 năm trước cách đây
mục cha
commit
62cbd1d4cd
96 tập tin đã thay đổi với 2801 bổ sung929 xóa
  1. 56 32
      app.py
  2. 3 3
      emergency_tool.py
  3. 3 3
      lang/en-US.json
  4. 3 3
      lang/ko-KR.json
  5. 20 8
      route/__init__.py
  6. 0 29
      route/api_recent_change.py
  7. 0 29
      route/api_search.py
  8. 29 3
      route/api_user_info.py
  9. 0 30
      route/api_w_raw.py
  10. 60 6
      route/api_w_render.py
  11. 5 19
      route/bbs_w_post.py
  12. 44 33
      route/edit.py
  13. 24 6
      route/edit_move.py
  14. 112 0
      route/edit_request.py
  15. 0 1
      route/edit_upload.py
  16. 16 5
      route/give_user_ban.py
  17. 24 0
      route/go_api_bbs.py
  18. 23 0
      route/go_api_func_ip.py
  19. 5 5
      route/go_api_func_sha224.py
  20. 25 0
      route/go_api_recent_change.py
  21. 25 0
      route/go_api_recent_edit_request.py
  22. 24 0
      route/go_api_search.py
  23. 22 92
      route/go_api_topic.py
  24. 18 0
      route/go_api_w_random.py
  25. 29 0
      route/go_api_w_raw.py
  26. 24 0
      route/go_api_w_xref.py
  27. 4 4
      route/go_main_func_easter_egg.py
  28. 0 18
      route/go_view_random.py
  29. 1 1
      route/main_search.py
  30. 12 16
      route/main_search_deep.py
  31. 5 1
      route/main_setting_acl.py
  32. 8 5
      route/main_sys_update.py
  33. 19 9
      route/recent_change.py
  34. 56 0
      route/recent_edit_request.py
  35. 0 1
      route/recent_history_add.py
  36. 3 6
      route/recent_history_tool.py
  37. 158 159
      route/tool/func.py
  38. 12 6
      route/tool/func_render.py
  39. 67 72
      route/tool/func_render_namumark.py
  40. 1 0
      route/tool/func_tool.py
  41. 31 35
      route/topic.py
  42. 0 13
      route/topic_list.py
  43. 6 14
      route/user_watch_list.py
  44. 25 13
      route/user_watch_list_name.py
  45. 64 60
      route/view_diff.py
  46. 9 0
      route/view_random.py
  47. 19 6
      route/view_raw.py
  48. 5 4
      route/view_set.py
  49. 17 16
      route/view_w.py
  50. 40 0
      route/view_w_raw.py
  51. 0 21
      route_go/api_func_sha224.go
  52. BIN
      route_go/bin/api_func_sha224.amd64.bin
  53. BIN
      route_go/bin/api_func_sha224.amd64.exe
  54. BIN
      route_go/bin/api_func_sha224.arm64.bin
  55. BIN
      route_go/bin/api_func_sha224.arm64.exe
  56. BIN
      route_go/bin/main.amd64.bin
  57. BIN
      route_go/bin/main.amd64.exe
  58. BIN
      route_go/bin/main.arm64.bin
  59. BIN
      route_go/bin/main.arm64.exe
  60. BIN
      route_go/bin/main_func_easter_egg.amd64.bin
  61. BIN
      route_go/bin/main_func_easter_egg.amd64.exe
  62. BIN
      route_go/bin/main_func_easter_egg.arm64.bin
  63. BIN
      route_go/bin/main_func_easter_egg.arm64.exe
  64. 4 0
      route_go/linux_amd64.sh
  65. 34 0
      route_go/main.go
  66. 101 0
      route_go/route/api_bbs.go
  67. 30 0
      route_go/route/api_func_ip.go
  68. 20 0
      route_go/route/api_func_sha224.go
  69. 112 0
      route_go/route/api_recent_change.go
  70. 122 0
      route_go/route/api_recent_edit_request.go
  71. 93 0
      route_go/route/api_search.go
  72. 130 0
      route_go/route/api_thread.go
  73. 15 9
      route_go/route/api_w_random.go
  74. 92 0
      route_go/route/api_w_raw.go
  75. 83 0
      route_go/route/api_w_xref.go
  76. 2 2
      route_go/route/main_func_easter_egg.go
  77. 0 0
      route_go/route/tool/db_connect.go
  78. 226 0
      route_go/route/tool/ip_parser.go
  79. 41 0
      route_go/route/tool/language.go
  80. 10 0
      route_go/route/tool/namumark.go
  81. 61 0
      route_go/route/tool/render.go
  82. 25 0
      route_go/route/tool/some_tool.go
  83. 33 0
      route_go/windows_amd64.ps1
  84. 2 2
      version.json
  85. 13 1
      views/main_css/css/main.css
  86. 49 6
      views/main_css/js/func/func.js
  87. 12 40
      views/main_css/js/func/insert_user_info.js
  88. 2 0
      views/main_css/js/route/bbs_w_post.js
  89. 85 10
      views/main_css/js/route/editor.js
  90. 0 50
      views/main_css/js/route/editor_sub.js
  91. 19 0
      views/main_css/js/route/render.js
  92. 161 0
      views/main_css/js/route/topic.js
  93. 0 20
      views/main_css/js/route/topic_sub.js
  94. 63 0
      views/main_css/js/route/view.js
  95. 3 0
      views/ringo/css/main.css
  96. 2 2
      views/ringo/index.html

+ 56 - 32
app.py

@@ -144,7 +144,7 @@ with get_db_connect() as conn:
     )
 
     app.config['JSON_AS_ASCII'] = False
-    app.config['JSONIFY_PRETTYPRINT_REGULAR'] = True
+    app.config['JSONIFY_PRETTYPRINT_REGULAR'] = False
     app.config['SEND_FILE_MAX_AGE_DEFAULT'] = 3600
 
     log = logging.getLogger('waitress')
@@ -486,9 +486,10 @@ app.route('/block_log/ongoing/<int:num>', defaults = { 'tool' : 'ongoing' })(rec
 
 # Func-history
 app.route('/recent_change', defaults = { 'tool' : 'recent' })(recent_change)
-app.route('/recent_change/<int:num>/<set_type>', defaults = { 'tool' : 'recent' })(recent_change)
 app.route('/recent_changes', defaults = { 'tool' : 'recent' })(recent_change)
-app.route('/recent_changes/<int:num>/<set_type>', defaults = { 'tool' : 'recent' })(recent_change)
+app.route('/recent_change/<int:num>/<set_type>', defaults = { 'tool' : 'recent' })(recent_change)
+
+app.route('/recent_edit_request', defaults = { 'db_set' : db_set_str })(recent_edit_request)
 
 app.route('/record/<name>', defaults = { 'tool' : 'record' })(recent_change)
 app.route('/record/<int:num>/<set_type>/<name>', defaults = { 'tool' : 'record' })(recent_change)
@@ -515,19 +516,19 @@ app.route('/xref_page/<int:num>/<everything:name>')(view_xref)
 app.route('/xref_this/<everything:name>', defaults = { 'xref_type' : 2 })(view_xref)
 app.route('/xref_this_page/<int:num>/<everything:name>', defaults = { 'xref_type' : 2 })(view_xref)
 
-app.route('/raw/<everything:name>')(view_raw_2)
-app.route('/raw_acl/<everything:name>', defaults = { 'doc_acl' : 1 })(view_raw_2)
-app.route('/raw_rev/<int:num>/<everything:name>')(view_raw_2)
+app.route('/raw/<everything:name>')(view_w_raw)
+app.route('/raw_acl/<everything:name>', defaults = { 'doc_acl' : 'on' })(view_w_raw)
+app.route('/raw_rev/<int:rev>/<everything:name>')(view_w_raw)
 
 app.route('/diff/<int(signed = True):num_a>/<int(signed = True):num_b>/<everything:name>')(view_diff)
 
 app.route('/down/<everything:name>')(view_down)
 
-app.route('/acl/<everything:name>', methods = ['POST', 'GET'])(view_acl)
+app.route('/acl/<everything:name>', methods = ['POST', 'GET'])(view_set)
 
 # everything 다음에 추가 붙은 경우에 대해서 재검토 필요 (진행중)
-app.route('/w_from/<everything:name>', defaults = { 'do_type' : 'from' })(view_read)
-app.route('/w/<everything:name>')(view_read)
+app.route('/w_from/<everything:name>', defaults = { 'do_type' : 'from' })(view_w)
+app.route('/w/<everything:name>')(view_w)
 
 app.route('/random', defaults = { 'db_set' : db_set_str })(view_random)
 
@@ -536,6 +537,11 @@ app.route('/edit/<everything:name>', methods = ['POST', 'GET'])(edit)
 app.route('/edit_from/<everything:name>', methods = ['POST', 'GET'], defaults = { 'do_type' : 'load' })(edit)
 app.route('/edit_section/<int:section>/<everything:name>', methods = ['POST', 'GET'])(edit)
 
+app.route('/edit_request/<everything:name>', methods = ['POST', 'GET'])(edit_request)
+app.route('/edit_request_from/<everything:name>', defaults = { 'do_type' : 'from' }, methods = ['POST', 'GET'])(edit_request)
+
+# app.route('/edit_request_rev/<int:rev>/<everything:name>', methods = ['POST', 'GET'])(edit_request)
+
 app.route('/upload', methods = ['POST', 'GET'])(edit_upload)
 
 # 개편 예정
@@ -567,7 +573,7 @@ app.route('/thread/<int:topic_num>/change', methods = ['POST', 'GET'])(topic_too
 app.route('/thread/<int:topic_num>/comment/<int:num>/tool')(topic_comment_tool)
 app.route('/thread/<int:topic_num>/comment/<int:num>/notice')(topic_comment_notice)
 app.route('/thread/<int:topic_num>/comment/<int:num>/blind')(topic_comment_blind)
-app.route('/thread/<int:topic_num>/comment/<int:num>/raw')(view_raw_2)
+app.route('/thread/<int:topic_num>/comment/<int:num>/raw')(view_raw)
 app.route('/thread/<int:topic_num>/comment/<int:num>/delete', methods = ['POST', 'GET'])(topic_comment_delete)
 
 # Func-user
@@ -603,9 +609,11 @@ app.route('/alarm/delete/<int:id>')(user_alarm_delete)
 
 app.route('/watch_list', defaults = { 'tool' : 'watch_list' })(user_watch_list)
 app.route('/watch_list/<everything:name>', defaults = { 'tool' : 'watch_list' })(user_watch_list_name)
+app.route('/watch_list_from/<everything:name>', defaults = { 'tool' : 'watch_list_from' })(user_watch_list_name)
 
 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_from/<everything:name>', defaults = { 'tool' : 'star_doc_from' })(user_watch_list_name)
 
 # 개편 보류중 S
 app.route('/change/email', methods = ['POST', 'GET'])(user_setting_email_2)
@@ -657,23 +665,32 @@ app.route('/bbs/w/<int:bbs_num>/<int:post_num>', methods = ['POST', 'GET'])(bbs_
 # app.route('/bbs/blind/<int:bbs_num>/<int:post_num>', methods = ['POST', 'GET'])(bbs_w_hide)
 app.route('/bbs/pinned/<int:bbs_num>/<int:post_num>', methods = ['POST', 'GET'])(bbs_w_pinned)
 app.route('/bbs/delete/<int:bbs_num>/<int:post_num>', methods = ['POST', 'GET'])(bbs_w_delete)
-app.route('/bbs/raw/<int:bbs_num>/<int:post_num>')(view_raw_2)
+app.route('/bbs/raw/<int:bbs_num>/<int:post_num>')(view_raw)
 app.route('/bbs/tool/<int:bbs_num>/<int:post_num>')(bbs_w_tool)
 app.route('/bbs/edit/<int:bbs_num>/<int:post_num>', methods = ['POST', 'GET'])(bbs_w_edit)
 app.route('/bbs/tool/<int:bbs_num>/<int:post_num>/<comment_num>')(bbs_w_comment_tool)
-app.route('/bbs/raw/<int:bbs_num>/<int:post_num>/<comment_num>')(view_raw_2)
+app.route('/bbs/raw/<int:bbs_num>/<int:post_num>/<comment_num>')(view_raw)
 app.route('/bbs/edit/<int:bbs_num>/<int:post_num>/<comment_num>', methods = ['POST', 'GET'])(bbs_w_edit)
 app.route('/bbs/delete/<int:bbs_num>/<int:post_num>/<comment_num>', methods = ['POST', 'GET'])(bbs_w_delete)
 
 # Func-api
-# app.route('/api/render_tool/<tool>/<everything:name>', methods = ['POST'])(api_w_render)
-# app.route('/api/render_tool/<tool>', methods = ['POST'])(api_w_render)
-app.route('/api/render/<everything:name>', methods = ['POST'])(api_w_render)
 app.route('/api/render', methods = ['POST'])(api_w_render)
+app.route('/api/render/<tool>', methods = ['POST'])(api_w_render)
 
-app.route('/api/raw_exist/<everything:name>', defaults = { 'exist_check' : 'on' })(api_w_raw)
-app.route('/api/raw_rev/<int(signed = True):rev>/<everything:name>')(api_w_raw)
-app.route('/api/raw/<everything:name>')(api_w_raw)
+app.route('/api/raw_exist/<everything:name>', defaults = { 'exist_check' : 'on', 'db_set' : db_set_str })(api_w_raw)
+app.route('/api/raw_rev/<int(signed = True):rev>/<everything:name>', defaults = { 'db_set' : db_set_str })(api_w_raw)
+app.route('/api/raw/<everything:name>', defaults = { 'db_set' : db_set_str })(api_w_raw)
+
+app.route('/api/xref/<everything:name>', defaults = { 'db_set' : db_set_str })(api_w_xref)
+app.route('/api/xref_page/<int:num>/<everything:name>', defaults = { 'db_set' : db_set_str })(api_w_xref)
+app.route('/api/xref_this/<everything:name>', defaults = { 'xref_type' : '2', 'db_set' : db_set_str })(api_w_xref)
+app.route('/api/xref_this_page/<int:num>/<everything:name>', defaults = { 'xref_type' : '2', 'db_set' : db_set_str })(api_w_xref)
+
+app.route('/api/random', defaults = { 'db_set' : db_set_str })(api_w_random)
+
+app.route('/api/bbs/main', defaults = { 'db_set' : db_set_str })(api_bbs)
+app.route('/api/bbs/w/<int:bbs_num>', defaults = { 'db_set' : db_set_str })(api_bbs)
+app.route('/api/bbs/w/<int:bbs_num>/<int:page>', defaults = { 'db_set' : db_set_str })(api_bbs)
 
 app.route('/api/bbs/w/<sub_code>')(api_bbs_w_post)
 app.route('/api/bbs/w/comment/<sub_code>')(api_bbs_w_comment)
@@ -685,25 +702,32 @@ app.route('/api/skin_info/<name>')(api_skin_info)
 app.route('/api/user_info/<user_name>')(api_user_info)
 app.route('/api/setting/<name>')(api_setting)
 
-app.route('/api/thread/<int:topic_num>/<tool>/<int:num>/<render>')(api_topic)
-app.route('/api/thread/<int:topic_num>/<tool>/<int:num>')(api_topic)
-app.route('/api/thread/<int:topic_num>/<tool>')(api_topic)
-app.route('/api/thread/<int:topic_num>')(api_topic)
+app.route('/api/thread/<int:topic_num>/<int:s_num>/<int:e_num>', defaults = { 'db_set' : db_set_str })(api_topic)
+app.route('/api/thread/<int:topic_num>/<tool>', defaults = { 'db_set' : db_set_str })(api_topic)
+app.route('/api/thread/<int:topic_num>', defaults = { 'db_set' : db_set_str })(api_topic)
+
+app.route('/api/search/<everything:name>', defaults = { 'db_set' : db_set_str })(api_search)
+app.route('/api/search_page/<int:num>/<everything:name>', defaults = { 'db_set' : db_set_str })(api_search)
+app.route('/api/search_data/<everything:name>', defaults = { 'search_type' : 'data', 'db_set' : db_set_str })(api_search)
+app.route('/api/search_data_page/<int:num>/<everything:name>', defaults = { 'search_type' : 'data', 'db_set' : db_set_str })(api_search)
 
-app.route('/api/search/<everything:name>/doc_num/<int:num>/<int:page>')(api_search)
-app.route('/api/search/<everything:name>')(api_search)
+app.route('/api/recent_change', defaults = { 'db_set' : db_set_str })(api_recent_change)
+app.route('/api/recent_changes', defaults = { 'db_set' : db_set_str })(api_recent_change)
+app.route('/api/recent_change/<int:limit>', defaults = { 'db_set' : db_set_str })(api_recent_change)
+app.route('/api/recent_change/<int:limit>/<set_type>/<int:num>', defaults = { 'db_set' : db_set_str })(api_recent_change)
 
-app.route('/api/recent_change/<int:num>')(api_recent_change)
-app.route('/api/recent_change')(api_recent_change)
-# recent_changes -> recent_change
-app.route('/api/recent_changes')(api_recent_change)
+app.route('/api/recent_edit_request', defaults = { 'db_set' : db_set_str })(api_recent_edit_request)
+app.route('/api/recent_edit_request/<int:limit>/<set_type>/<int:num>', defaults = { 'db_set' : db_set_str })(api_recent_edit_request)
 
+# 곧 개편 당할 곳
 app.route('/api/recent_discuss/<get_type>/<int:num>')(api_recent_discuss)
 app.route('/api/recent_discuss/<int:num>')(api_recent_discuss)
 app.route('/api/recent_discuss')(api_recent_discuss)
+##
 
 app.route('/api/lang/<data>')(api_func_lang)
 app.route('/api/sha224/<everything:data>')(api_func_sha224)
+app.route('/api/ip/<everything:data>', defaults = { 'db_set' : db_set_str })(api_func_ip)
 
 app.route('/api/image/<everything:name>')(api_image_view)
 
@@ -716,10 +740,10 @@ app.route('/manager/<int:num>/<everything:add_2>', methods = ['POST', 'GET'])(ma
 # app.route('/guide/<doc_name>')(main_tool_guide)
 
 app.route('/search', methods=['POST'])(main_search)
-app.route('/search/<everything:name>', methods = ['POST', 'GET'])(main_search_deep)
-app.route('/search/<int:num>/<everything:name>', methods = ['POST', 'GET'])(main_search_deep)
-app.route('/search_data/<everything:name>', defaults = { 'search_type' : 'data' }, methods = ['POST', 'GET'])(main_search_deep)
-app.route('/search_data/<int:num>/<everything:name>', defaults = { 'search_type' : 'data' }, methods = ['POST', 'GET'])(main_search_deep)
+app.route('/search/<everything:name>', defaults = { 'db_set' : db_set_str }, methods = ['POST', 'GET'])(main_search_deep)
+app.route('/search_page/<int:num>/<everything:name>', defaults = { 'db_set' : db_set_str }, methods = ['POST', 'GET'])(main_search_deep)
+app.route('/search_data/<everything:name>', defaults = { 'search_type' : 'data', 'db_set' : db_set_str }, methods = ['POST', 'GET'])(main_search_deep)
+app.route('/search_data_page/<int:num>/<everything:name>', defaults = { 'search_type' : 'data', 'db_set' : db_set_str }, methods = ['POST', 'GET'])(main_search_deep)
 app.route('/goto', methods=['POST'])(main_search_goto)
 app.route('/goto/<everything:name>', methods=['GET', 'POST'])(main_search_goto)
 

+ 3 - 3
emergency_tool.py

@@ -51,7 +51,7 @@ print('22. Delete body top')
 print('23. Delete body bottom')
 print('24. SQLite to MySQL')
 
-what_i_do = input('Select : ')
+what_i_do = input('Insert selection number (EX : 9) : ')
 if what_i_do == '1':
     go_num = input('All delete (Y) [Y, N] : ')
     if not go_num == 'N':
@@ -179,7 +179,7 @@ elif what_i_do == '18':
 
     curs.execute(db_change("update other set data = ? where name = 'wiki_access_password'"), [wiki_access_password])
 elif what_i_do == '19':
-    up_data = input('Insert branch (beta) [stable, beta, dev] : ')
+    up_data = input('Insert branch name (beta) [stable, beta, dev] : ')
 
     if not up_data in ['stable', 'beta', 'dev']:
         up_data = 'beta'
@@ -189,7 +189,7 @@ elif what_i_do == '19':
 
         ok += [os.system('git remote rm origin')]
         ok += [os.system('git remote add origin https://github.com/opennamu/opennamu.git')]
-        ok += [os.system('git fetch origin ' + up_data)]
+        ok += [os.system('git fetch --depth=1 origin ' + up_data)]
         ok += [os.system('git reset --hard origin/' + up_data)]
         if (ok[0] and ok[1] and ok[2] and ok[3]) != 0:
             print('Error : update failed')

+ 3 - 3
lang/en-US.json

@@ -206,8 +206,8 @@
         "old_page" : "Document(s) modified a long time ago",
         "skin_set" : "Skin setting(s)",
         "many_delete" : "Document bulk delete",
-        "edit_req" : "Edit request",
-        "edit_req_check" : "Check edit request",
+        "edit_request" : "Edit request",
+        "edit_request_check" : "Check edit request",
         "accept_edit_request" : "Accept edit request",
         "history_add" : "Add history",
         "all_register_num" : "The number of application forms",
@@ -554,7 +554,7 @@
                 "view_acl" : "Reading ACL",
                 "user_document_acl" : "User document ACL",
                 "upload_acl" : "Upload ACL",
-                "edit_req_acl" : "Edit request ACL",
+                "edit_request_acl" : "Edit request ACL",
                 "many_upload_acl" : "Upload multiple files ACL",
                 "vote_acl" : "Vote ACL",
         "_comment_2.7_" : "Application list",

+ 3 - 3
lang/ko-KR.json

@@ -301,8 +301,8 @@
     "content": "내용",
     "upload_acl": "파일 올리기 ACL",
     "topic_delete": "토론 삭제",
-    "edit_req": "편집 요청",
-    "edit_req_check": "편집 요청 검사",
+    "edit_request": "편집 요청",
+    "edit_request_check": "편집 요청 검사",
     "sqlite_only": "SQLite만",
     "off": "끄기",
     "slow_edit": "편집 속도 제한 시간",
@@ -311,7 +311,7 @@
     "public_key": "공개 키",
     "fast_edit_error": "편집 속도가 너무 빠릅니다. 제한 (초) : ",
     "main_acl_setting": "기본 ACL 설정",
-    "edit_req_acl": "편집 요청 ACL",
+    "edit_request_acl": "편집 요청 ACL",
     "application_list": "가입신청 목록",
     "application_time": "가입신청 일시",
     "answer": "답변",

+ 20 - 8
route/__init__.py

@@ -1,12 +1,8 @@
 from route.api_func_lang import api_func_lang
 from route.api_image_view import api_image_view
-from route.api_w_raw import api_w_raw
-from route.api_recent_change import api_recent_change
 from route.api_recent_discuss import api_recent_discuss
-from route.api_search import api_search
 from route.api_setting import api_setting
 from route.api_skin_info import api_skin_info
-from route.api_topic import api_topic
 from route.api_user_info import api_user_info
 from route.api_version import api_version
 from route.api_w_render import api_w_render
@@ -35,6 +31,7 @@ from route.edit_delete_multiple import edit_delete_multiple
 from route.edit_move import edit_move
 from route.edit_revert import edit_revert
 from route.edit_upload import edit_upload
+from route.edit_request import edit_request
 
 from route.filter_all import filter_all
 from route.filter_all_add import filter_all_add
@@ -109,6 +106,7 @@ from route.recent_app_submit import recent_app_submit_2
 
 from route.recent_block import recent_block
 from route.recent_change import recent_change
+from route.recent_edit_request import recent_edit_request
 from route.recent_discuss import recent_discuss
 from route.recent_history_add import recent_history_add
 from route.recent_history_delete import recent_history_delete
@@ -155,12 +153,14 @@ from route.user_setting_user_name import user_setting_user_name
 from route.user_watch_list import user_watch_list
 from route.user_watch_list_name import user_watch_list_name
 
-from route.view_acl import view_acl
+from route.view_set import view_set
 from route.view_diff import view_diff
 from route.view_down import view_down
-from route.view_raw import view_raw_2
-from route.view_read import view_read
+from route.view_raw import view_raw
+from route.view_w_raw import view_w_raw
+from route.view_w import view_w
 from route.view_xref import view_xref
+from route.view_random import view_random
 
 from route.vote_add import vote_add
 from route.vote_close import vote_close
@@ -169,7 +169,19 @@ from route.vote_list import vote_list
 from route.vote_select import vote_select
 
 from route.go_api_func_sha224 import api_func_sha224
+from route.go_api_func_ip import api_func_ip
 
-from route.go_view_random import view_random
+from route.go_api_search import api_search
+
+from route.go_api_recent_change import api_recent_change
+from route.go_api_recent_edit_request import api_recent_edit_request
+
+from route.go_api_bbs import api_bbs
+
+from route.go_api_topic import api_topic
+
+from route.go_api_w_raw import api_w_raw
+from route.go_api_w_random import api_w_random
+from route.go_api_w_xref import api_w_xref
 
 from route.go_main_func_easter_egg import main_func_easter_egg

+ 0 - 29
route/api_recent_change.py

@@ -1,29 +0,0 @@
-from .tool.func import *
-
-def api_recent_change(num = 10):
-    with get_db_connect() as conn:
-        curs = conn.cursor()
-
-        num = 50 if (1 if not num > 0 else num) > 50 else num
-        admin = admin_check(6)
-
-        data_list = []
-
-        curs.execute(db_change('select id, title from rc where type = "normal" order by date desc limit ?'), [num])
-        for for_a in curs.fetchall():
-            curs.execute(db_change('select id, title, date, ip, send, leng, hide from history where id = ? and title = ?'), for_a)
-            db_data = curs.fetchall()
-            if db_data:
-                db_data = list(db_data[0])
-                if db_data[6] == '' or admin == 1:
-                    if admin == 1:
-                        data_list += [db_data]
-                    else:
-                        db_data[3] = ip_pas(db_data[3], 1)
-                        data_list += [db_data]
-                else:
-                    data_list += [['', '', '', '', '', '', db_data[6]]]
-            else:
-                data_list += [['', '', '', '', '', '', '']]
-
-        return flask.jsonify(data_list if data_list else {}) 

+ 0 - 29
route/api_search.py

@@ -1,29 +0,0 @@
-from .tool.func import *
-
-def api_search(name = 'Test', num = 10, page = 1):
-    with get_db_connect() as conn:
-        curs = conn.cursor()
-
-        num = 1 if num > 1000 else num
-        page = (page * (num - 1)) if page * num > 0 else 0
-
-        # 개편 예정
-        curs.execute(db_change('select data from other where name = "count_all_title"'))
-        if int(curs.fetchall()[0][0]) < 30000:
-            curs.execute(db_change("" + \
-                "select distinct title, case " + \
-                "when title like ? then 'title' else 'data' end from data " + \
-                "where (title like ? or data like ?) order by case " + \
-                "when title like ? then 1 else 2 end limit ?, ?"),
-                ['%' + name + '%', '%' + name + '%', '%' + name + '%', '%' + name + '%', page, num]
-            )
-        else:
-            curs.execute(db_change("select title from data where title like ? order by title limit ?, ?"),
-                ['%' + name + '%', page, num]
-            )
-            
-        all_list = curs.fetchall()
-        if all_list:
-            return flask.jsonify(all_list)
-        else:
-            return flask.jsonify({})

+ 29 - 3
route/api_user_info.py

@@ -49,7 +49,9 @@ def api_user_info(user_name = ''):
                     regex_ban = 1
                     
                     data_result['ban']['type'] = 'regex'
-                    if db_data[0] == 'O':
+                    if db_data[0] == 'E':
+                        data_result['ban']['login_able'] = '2'
+                    elif db_data[0] == 'O':
                         data_result['ban']['login_able'] = '1'
                     else:
                         data_result['ban']['login_able'] = '0'
@@ -68,7 +70,9 @@ def api_user_info(user_name = ''):
                 db_data = curs.fetchall()
                 if db_data:
                     data_result['ban']['type'] = 'normal'
-                    if db_data[0][0] == 'O':
+                    if db_data[0][0] == 'E':
+                        data_result['ban']['login_able'] = '2'
+                    elif db_data[0][0] == 'O':
                         data_result['ban']['login_able'] = '1'
                     else:
                         data_result['ban']['login_able'] = '0'
@@ -94,5 +98,27 @@ def api_user_info(user_name = ''):
             data_result['user_title'] = db_data[0][0]
         else:
             data_result['user_title'] = ''
+
+        lang_data_list = [
+            'user_name',
+            'authority',
+            'state',
+            'member',
+            'normal',
+            'blocked',
+            'type',
+            'regex',
+            'period',
+            'limitless',
+            'login_able',
+            'why',
+            'band_blocked',
+            'ip',
+            'ban',
+            'level',
+            'option',
+            'edit_request_able'
+        ]
+        lang_data = { for_a : load_lang(for_a) for for_a in lang_data_list }
                 
-        return flask.jsonify({ 'data' : data_result })
+        return flask.jsonify({ 'data' : data_result, 'language' : lang_data })

+ 0 - 30
route/api_w_raw.py

@@ -1,30 +0,0 @@
-from .tool.func import *
-
-def api_w_raw(name = 'Test', rev = '', exist_check = ''):
-    with get_db_connect() as conn:
-        curs = conn.cursor()
-
-        if exist_check != '':
-            curs.execute(db_change("select title from data where title = ?"), [name])
-            if curs.fetchall():
-                return flask.jsonify({ 'exist' : '1' })
-            else:
-                return flask.jsonify({})
-        else:
-            if rev != '':
-                curs.execute(db_change("select data from history where title = ? and id = ?"), [name, rev])
-            else:
-                curs.execute(db_change("select data from data where title = ?"), [name])
-
-            data = curs.fetchall()
-            if data:
-                return flask.jsonify({
-                    "title" : name, 
-                    "data" : render_set(
-                        doc_name = name, 
-                        doc_data = data[0][0],
-                        data_type = 'raw'
-                    )
-                })
-            else:
-                return flask.jsonify({})

+ 60 - 6
route/api_w_render.py

@@ -1,16 +1,70 @@
 from .tool.func import *
 
-def api_w_render(name = ''):
+class api_w_render_include:
+    def __init__(self, data_option):
+        self.include_change_list = data_option
+
+    def __call__(self, match):
+        match_org = match.group(0)
+        match = match.groups()
+
+        if len(match) < 3:
+            match = list(match) + ['']
+
+        if match[2] == '\\':
+            return match_org
+        else:
+            slash_add = ''
+            if match[0]:
+                if len(match[0]) % 2 == 1:
+                    slash_add = '\\' * (len(match[0]) - 1)
+                else:
+                    slash_add = match[0]
+
+            if match[1] in self.include_change_list:
+                return slash_add + self.include_change_list[match[1]]
+            else:
+                return slash_add + match[2]
+
+def api_w_render(name = '', tool = ''):
     with get_db_connect() as conn:
         curs = conn.cursor()
 
         if flask.request.method == 'POST':
+            name = flask.request.form.get('name', '')
             data_org = flask.request.form.get('data', '')
-            data_pas = render_set(
-                doc_name = name, 
-                doc_data = data_org, 
-                data_type = 'api_view'
-            )
+            
+            data_option = flask.request.form.get('option', '')
+            if data_option != '':
+                data_option = json.loads(data_option)
+
+                data_option_func = api_w_render_include(data_option)
+
+                # parameter replace
+                data_org = re.sub(r'(\\+)?@([ㄱ-힣a-zA-Z0-9]+)=((?:\\@|[^@\n])+)@', data_option_func, data_org)
+                data_org = re.sub(r'(\\+)?@([ㄱ-힣a-zA-Z0-9]+)@', data_option_func, data_org)
+
+                # remove end br
+                data_org = re.sub('^\n+', '', data_org)
+
+            if tool == '':
+                data_pas = render_set(
+                    doc_name = name, 
+                    doc_data = data_org, 
+                    data_type = 'api_view'
+                )
+            elif tool == 'include':
+                data_pas = render_set(
+                    doc_name = name, 
+                    doc_data = data_org, 
+                    data_type = 'api_include'
+                )
+            else:
+                data_pas = render_set(
+                    doc_name = name,
+                    doc_data = data_org, 
+                    data_type = 'api_thread'
+                )
 
             return flask.jsonify({
                 "data" : data_pas[0], 

+ 5 - 19
route/bbs_w_post.py

@@ -2,7 +2,7 @@ from .tool.func import *
 
 from .api_bbs_w_post import api_bbs_w_post
 from .api_bbs_w_comment import api_bbs_w_comment
-from .api_topic import api_topic_thread_make, api_topic_thread_pre_render
+from .go_api_topic import api_topic_thread_make, api_topic_thread_pre_render
 
 from .edit import edit_editor
 
@@ -36,10 +36,7 @@ def bbs_w_post_comment(user_id, sub_code, comment_num, bbs_num_str, post_num_str
             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
-                ),
+                render_set(doc_data = temp_dict['comment']),
                 sub_code_check,
                 color = color,
                 add_style = 'width: calc(100% - ' + str(margin_count * 20) + 'px);'
@@ -132,11 +129,7 @@ def bbs_w_post(bbs_num = '', post_num = ''):
                 data += api_topic_thread_make(
                     ip_pas(temp_dict['user_id']),
                     date,
-                    render_set(
-                        doc_data = temp_dict['data'],
-                        data_type = 'thread',
-                        data_in = 'bbs'
-                    ),
+                    render_set(doc_data = temp_dict['data'], data_type = 'thread'),
                     '0',
                     color = 'green'
                 )
@@ -159,11 +152,7 @@ def bbs_w_post(bbs_num = '', post_num = ''):
                     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)
-                        ),
+                        render_set(doc_data = temp_dict['comment'], data_type = 'thread'),
                         str(count),
                         color = color
                     )
@@ -262,10 +251,7 @@ def bbs_w_post(bbs_num = '', post_num = ''):
                 data += api_topic_thread_make(
                     ip_pas(temp_dict['user_id']),
                     date,
-                    render_set(
-                        doc_data = temp_dict['data'],
-                        data_in = 'bbs'
-                    ),
+                    render_set(doc_data = temp_dict['data']),
                     '0',
                     color = 'red'
                 )

+ 44 - 33
route/edit.py

@@ -26,7 +26,6 @@ def edit_timeout(func, args = (), timeout = 3):
 def edit_editor(curs, ip, data_main = '', do_type = 'edit', addon = ''):
     monaco_editor_top = ''
     editor_display = ''
-    add_get_file = ''
     monaco_display = ''
 
     if do_type == 'edit':
@@ -51,11 +50,6 @@ def edit_editor(curs, ip, data_main = '', do_type = 'edit', addon = ''):
     
     monaco_editor_top += '<a href="javascript:opennamu_do_editor_temp_save();">(' + load_lang('load_temp_save') + ')</a> <a href="javascript:opennamu_do_editor_temp_save_load();">(' + load_lang('load_temp_save_load') + ')</a> '
     monaco_editor_top += '<a href="javascript:opennamu_edit_turn_off_monaco();">(' + load_lang('turn_off_monaco') + ')</a>'
-
-    add_get_file = '''
-        <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.41.0/min/vs/editor/editor.main.min.css" integrity="sha512-MFDhxgOYIqLdcYTXw7en/n5BshKoduTitYmX8TkQ+iJOGjrWusRi8+KmfZOrgaDrCjZSotH2d1U1e/Z1KT6nWw==" crossorigin="anonymous" referrerpolicy="no-referrer" />
-        <script src="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.41.0/min/vs/loader.min.js" integrity="sha512-A+6SvPGkIN9Rf0mUXmW4xh7rDvALXf/f0VtOUiHlDUSPknu2kcfz1KzLpOJyL2pO+nZS13hhIjLqVgiQExLJrw==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
-    '''
     
     darkmode = flask.request.cookies.get('main_css_darkmode', '0')
     monaco_thema = 'vs-dark' if darkmode == '1' else ''
@@ -70,7 +64,7 @@ def edit_editor(curs, ip, data_main = '', do_type = 'edit', addon = ''):
 
     textarea_size = 'opennamu_textarea_500' if do_type == 'edit' else 'opennamu_textarea_100'
 
-    return add_get_file + '''
+    return '''
         <textarea style="display: none;" id="opennamu_edit_origin" name="doc_data_org">''' + html.escape(data_main) + '''</textarea>
         <div>
             ''' + monaco_editor_top + '''
@@ -103,15 +97,21 @@ def edit(name = 'Test', section = 0, do_type = ''):
         curs = conn.cursor()
     
         ip = ip_check()
+
+        edit_req_mode = 0
         if acl_check(name, 'document_edit') == 1:
-            return redirect('/raw_acl/' + url_pas(name))
-        
+            edit_req_mode = 1
+            
         if do_title_length_check(name) == 1:
             return re_error('/error/38')
         
         curs.execute(db_change("select id from history where title = ? order by id + 0 desc"), [name])
         doc_ver = curs.fetchall()
         doc_ver = doc_ver[0][0] if doc_ver else '0'
+
+        curs.execute(db_change("select set_data from data_set where doc_name = ? and doc_rev = ? and set_name = 'edit_request_data'"), [name, doc_ver])
+        if curs.fetchall():
+            return redirect('/edit_request_from/' + url_pas(name))
         
         section = '' if section == 0 else section
         post_ver = flask.request.form.get('ver', '')
@@ -180,7 +180,6 @@ def edit(name = 'Test', section = 0, do_type = ''):
             curs.execute(db_change("select data from other where name = 'edit_timeout'"))
             db_data_2 = curs.fetchall()
             db_data_2 = number_check(db_data_2[0][0]) if db_data_2 and db_data_2[0][0] != '' else ''
-
             if db_data_2 != '' and platform.system() == 'Linux':
                 timeout = edit_timeout(edit_render_set, (name, content), timeout = int(db_data_2))
             else:
@@ -189,29 +188,40 @@ def edit(name = 'Test', section = 0, do_type = ''):
             if timeout == 1:
                 return re_error('/error/41')
             
-            if db_data:
-                curs.execute(db_change("update data set data = ? where title = ?"), [content, name])
-            else:    
+            if edit_req_mode == 0:
+                # 진짜 기록 부분
+                curs.execute(db_change("delete from data where title = ?"), [name])
                 curs.execute(db_change("insert into data (title, data) values (?, ?)"), [name, content])
-    
-            curs.execute(db_change("select user from scan where title = ? and type = ''"), [name])
-            for scan_user in curs.fetchall():
-                add_alarm(scan_user[0], ip, '<a href="/w/' + url_pas(name) + '">' + html.escape(name) + '</a>')
-                    
-            history_plus(
-                name,
-                content,
-                today,
-                ip,
-                send,
-                leng
-            )
-            
-            render_set(
-                doc_name = name,
-                doc_data = content,
-                data_type = 'backlink'
-            )
+        
+                curs.execute(db_change("select id from user_set where name = 'watchlist' and data = ?"), [name])
+                for scan_user in curs.fetchall():
+                    add_alarm(scan_user[0], ip, '<a href="/w/' + url_pas(name) + '">' + html.escape(name) + '</a>')
+                        
+                history_plus(
+                    name,
+                    content,
+                    today,
+                    ip,
+                    send,
+                    leng
+                )
+                
+                render_set(
+                    doc_name = name,
+                    doc_data = content,
+                    data_type = 'backlink'
+                )
+            else:
+                curs.execute(db_change("insert into data_set (doc_name, doc_rev, set_name, set_data) values (?, ?, 'edit_request_data', ?)"), [name, doc_ver, content])
+                curs.execute(db_change("insert into data_set (doc_name, doc_rev, set_name, set_data) values (?, ?, 'edit_request_user', ?)"), [name, doc_ver, ip])
+                curs.execute(db_change("insert into data_set (doc_name, doc_rev, set_name, set_data) values (?, ?, 'edit_request_date', ?)"), [name, doc_ver, today])
+                curs.execute(db_change("insert into data_set (doc_name, doc_rev, set_name, set_data) values (?, ?, 'edit_request_send', ?)"), [name, doc_ver, send])
+                curs.execute(db_change("insert into data_set (doc_name, doc_rev, set_name, set_data) values (?, ?, 'edit_request_leng', ?)"), [name, doc_ver, leng])
+                curs.execute(db_change("insert into data_set (doc_name, doc_rev, set_name, set_data) values (?, ?, 'edit_request_doing', ?)"), [name, doc_ver, today])
+
+                curs.execute(db_change("select id from user_set where name = 'watchlist' and data = ?"), [name])
+                for scan_user in curs.fetchall():
+                    add_alarm(scan_user[0], ip, '<a href="/edit_request/' + url_pas(name) + '">' + html.escape(name) + '</a> edit_request')
             
             conn.commit()
             
@@ -316,9 +326,10 @@ def edit(name = 'Test', section = 0, do_type = ''):
                 editor_top_text += '<hr class="main_hr">'
 
             sub_menu = ' (' + str(section) + ')' if section != '' else ''
+            sub_title = '(' + load_lang('edit_request') + ')' if edit_req_mode == 1 else '(' + load_lang('edit') + ')'
 
             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([sub_title + sub_menu, 0])],
                 data = editor_top_text + '''
                     <form method="post">
                         <textarea style="display: none;" name="doc_section_data_where">''' + data_section_where + '''</textarea>

+ 24 - 6
route/edit_move.py

@@ -77,8 +77,14 @@ def edit_move(name):
                         curs.execute(db_change("update rc set title = ?, id = ? where title = ? and id = ?"), [move_title, str(int(num) + int(move[0])), name, move[0]])
                         curs.execute(db_change("update history set title = ?, id = ? where title = ? and id = ?"), [move_title, str(int(num) + int(move[0])), name, move[0]])
 
-                    history_plus(move_title, data_in, time, ip, send, '0',
-                        t_check = 'merge <a>' + name + '</a> - <a>' + move_title + '</a> move',
+                    history_plus(
+                        move_title, 
+                        data_in, 
+                        time, 
+                        ip, 
+                        send, 
+                        '0',
+                        t_check = '<a>' + name + '</a> ↔ <a>' + move_title + '</a>',
                         mode = 'move'
                     )
                 elif move_option == 'reverse':
@@ -107,8 +113,14 @@ def edit_move(name):
                         data = curs.fetchall()
                         data_in = data[0][0] if data else ''
 
-                        history_plus(title_name[0], data_in, time, ip, send, '0',
-                            t_check = '<a>' + title_name[0] + '</a> - <a>' + title_name[1] + '</a> move',
+                        history_plus(
+                            title_name[0], 
+                            data_in, 
+                            time, 
+                            ip, 
+                            send, 
+                            '0',
+                            t_check = '<a>' + title_name[0] + '</a> → <a>' + title_name[1] + '</a>',
                             mode = 'move'
                         )
                 elif move_option != 'none':
@@ -134,8 +146,14 @@ def edit_move(name):
                 curs.execute(db_change("update rc set title = ? where title = ?"), [move_title, name])
                 # 역사와 최근 변경 이동 E
 
-                history_plus(move_title, data_in, time, ip, send, '0',
-                    t_check = '<a>' + name + '</a> - <a>' + move_title + '</a> move',
+                history_plus(
+                    move_title, 
+                    data_in, 
+                    time, 
+                    ip, 
+                    send,
+                    '0',
+                    t_check = '<a>' + name + '</a> → <a>' + move_title + '</a>',
                     mode = 'move'
                 )
 

+ 112 - 0
route/edit_request.py

@@ -0,0 +1,112 @@
+from .tool.func import *
+
+from .view_diff import view_diff_do
+
+def edit_request(name = 'Test', do_type = ''):
+    with get_db_connect() as conn:
+        curs = conn.cursor()
+
+        disabled = ""
+        if acl_check(name, 'document_edit') == 1:
+            disabled = "disabled"
+
+        curs.execute(db_change("select id from history where title = ? order by id + 0 desc"), [name])
+        doc_ver = curs.fetchall()
+        doc_ver = doc_ver[0][0] if doc_ver else '0'
+
+        curs.execute(db_change("select set_data from data_set where doc_name = ? and doc_rev = ? and set_name = 'edit_request_data'"), [name, doc_ver])
+        db_data = curs.fetchall()
+        if not db_data:
+            return redirect('/edit/' + url_pas(name))
+        
+        edit_request_data = db_data[0][0]
+
+        curs.execute(db_change("select set_data from data_set where doc_name = ? and doc_rev = ? and set_name = 'edit_request_user'"), [name, doc_ver])
+        db_data = curs.fetchall()
+        edit_request_user = db_data[0][0] if db_data else ''
+
+        curs.execute(db_change("select set_data from data_set where doc_name = ? and doc_rev = ? and set_name = 'edit_request_date'"), [name, doc_ver])
+        db_data = curs.fetchall()
+        edit_request_date = db_data[0][0] if db_data else ''
+
+        curs.execute(db_change("select set_data from data_set where doc_name = ? and doc_rev = ? and set_name = 'edit_request_send'"), [name, doc_ver])
+        db_data = curs.fetchall()
+        edit_request_send = db_data[0][0] if db_data else ''
+
+        curs.execute(db_change("select set_data from data_set where doc_name = ? and doc_rev = ? and set_name = 'edit_request_leng'"), [name, doc_ver])
+        db_data = curs.fetchall()
+        edit_request_leng = db_data[0][0] if db_data else ''
+
+        if flask.request.method == 'POST':
+            if acl_check(name, 'document_edit') == 1:
+                return redirect('/w/' + url_pas(name))
+            
+            curs.execute(db_change("select data from data where title = ?"), [name])
+            db_data = curs.fetchall()
+            o_data = db_data[0][0] if db_data else ''
+            
+            curs.execute(db_change("select id from user_set where name = 'watchlist' and data = ?"), [name])
+            for scan_user in curs.fetchall():
+                add_alarm(scan_user[0], edit_request_user, '<a href="/w/' + url_pas(name) + '">' + html.escape(name) + '</a>')
+
+            if flask.request.form.get('check', '') == 'Y':
+                curs.execute(db_change("delete from data where title = ?"), [name])
+                curs.execute(db_change("insert into data (title, data) values (?, ?)"), [name, edit_request_data])
+                        
+                history_plus(
+                    name,
+                    edit_request_data,
+                    edit_request_date,
+                    edit_request_user,
+                    edit_request_send,
+                    edit_request_leng,
+                    mode = 'edit_request'
+                )
+                
+                render_set(
+                    doc_name = name,
+                    doc_data = edit_request_data,
+                    data_type = 'backlink'
+                )
+            else:
+                history_plus(
+                    name,
+                    edit_request_data,
+                    edit_request_date,
+                    edit_request_user,
+                    edit_request_send,
+                    '0',
+                    mode = 'edit_request'
+                )
+                
+            if do_type == 'from':
+                return redirect('/edit/' + url_pas(name))
+            else:
+                return redirect('/w/' + url_pas(name))
+        else:
+            curs.execute(db_change("select data from data where title = ?"), [name])
+            db_data = curs.fetchall()
+            old_data = db_data[0][0] if db_data else ''
+
+            result = view_diff_do(old_data, edit_request_data, 'r' + doc_ver, load_lang('edit_request'))
+
+            return easy_minify(flask.render_template(skin_check(), 
+                imp = [name, wiki_set(), wiki_custom(), wiki_css(['(' + load_lang('edit_request_check') + ')', 0])],
+                data = '''
+                    <div id="opennamu_get_user_info">''' + html.escape(edit_request_user) + '''</div>
+                    <hr class="main_hr">
+                    ''' + edit_request_date + '''
+                    <hr class="main_hr">
+                    <input readonly value="''' + html.escape(edit_request_send) + '''">
+                    <hr class="main_hr">
+                    ''' + result + '''
+                    <hr class="main_hr">
+                    <form method="post">
+                        <button ''' + disabled + ''' id="opennamu_save_button" type="submit" name="check" value="Y">''' + load_lang('approve') + '''</button>
+                        <button ''' + disabled + ''' id="opennamu_preview_button" type="submit" name="check" value="">''' + load_lang('decline') + '''</button>
+                        <hr class="main_hr">
+                        <textarea readonly class="opennamu_textarea_500">''' + html.escape(edit_request_data) + '''</textarea>
+                    </form>
+                ''',
+                menu = 0
+            ))

+ 0 - 1
route/edit_upload.py

@@ -105,7 +105,6 @@ def edit_upload():
                     ip,
                     '',
                     '0',
-                    t_check = 'upload',
                     mode = 'upload'
                 )
 

+ 16 - 5
route/give_user_ban.py

@@ -21,10 +21,18 @@ def give_user_ban(name = None, ban_type = ''):
                 end = '0'
             
             regex_get = flask.request.form.get('regex', None)
-            login = flask.request.form.get('login', '')
             why = flask.request.form.get('why', '')
 
-            release = flask.request.form.get('release', '')
+            release = ''
+            login = ''
+            
+            ban_option = flask.request.form.get('ban_option', '')
+            if ban_option == 'login_able':
+                login = 'O'
+            elif ban_option == 'edit_request_able':
+                login = 'E'
+            elif ban_option == 'release':
+                release = '1'
 
             if ban_type == 'multiple':
                 all_user = re.findall(r'([^\n]+)\n', flask.request.form.get('name', 'test').replace('\r', '') + '\n')
@@ -106,9 +114,12 @@ def give_user_ban(name = None, ban_type = ''):
                         <hr class="main_hr">
                         <input placeholder="''' + load_lang('why') + '''" name="why" type="text">
                         <hr class="main_hr">
-                        <input type="checkbox" name="login"> ''' + load_lang('login_able') + '''
-                        <hr class="main_hr">
-                        <input type="checkbox" name="release"> ''' + load_lang('release') + '''
+                        <select name="ban_option">
+                            <option value="">''' + load_lang('default') + '''</option>
+                            <option value="login_able">''' + load_lang('login_able') + '''</option>
+                            <option value="edit_request_able">''' + load_lang('edit_request_able') + '''</option>
+                            <option value="release">''' + load_lang('release') + '''</option>
+                        </select>
                         <hr class="main_hr">
                         <button type="submit">''' + load_lang('save') + '''</button>
                     </form>

+ 24 - 0
route/go_api_bbs.py

@@ -0,0 +1,24 @@
+from .tool.func import *
+
+def api_bbs(db_set, bbs_num = "", page = 1):
+    with get_db_connect() as conn:
+        other_set = {}
+        other_set["bbs_num"] = str(bbs_num)
+        other_set["page"] = str(page)
+        other_set["ip"] = ip_check()
+        other_set = json.dumps(other_set)
+
+        if platform.system() == 'Linux':
+            if platform.machine() in ["AMD64", "x86_64"]:
+                data = subprocess.Popen([os.path.join(".", "route_go", "bin", "main.amd64.bin"), sys._getframe().f_code.co_name, db_set, other_set], stdout = subprocess.PIPE).communicate()[0]
+            else:
+                data = subprocess.Popen([os.path.join(".", "route_go", "bin", "main.arm64.bin"), sys._getframe().f_code.co_name, db_set, other_set], stdout = subprocess.PIPE).communicate()[0]
+        else:
+            if platform.machine() in ["AMD64", "x86_64"]:
+                data = subprocess.Popen([os.path.join(".", "route_go", "bin", "main.amd64.exe"), sys._getframe().f_code.co_name, db_set, other_set], stdout = subprocess.PIPE).communicate()[0]
+            else:
+                data = subprocess.Popen([os.path.join(".", "route_go", "bin", "main.arm64.exe"), sys._getframe().f_code.co_name, db_set, other_set], stdout = subprocess.PIPE).communicate()[0]
+
+        data = data.decode('utf8')
+
+        return flask.Response(response = data, status = 200, mimetype = 'application/json')

+ 23 - 0
route/go_api_func_ip.py

@@ -0,0 +1,23 @@
+from .tool.func import *
+
+def api_func_ip(db_set, data = 'Test'):
+    with get_db_connect() as conn:
+        other_set = {}
+        other_set["data"] = data
+        other_set["ip"] = ip_check()
+        other_set = json.dumps(other_set)
+
+        if platform.system() == 'Linux':
+            if platform.machine() in ["AMD64", "x86_64"]:
+                data = subprocess.Popen([os.path.join(".", "route_go", "bin", "main.amd64.bin"), sys._getframe().f_code.co_name, db_set, other_set], stdout = subprocess.PIPE).communicate()[0]
+            else:
+                data = subprocess.Popen([os.path.join(".", "route_go", "bin", "main.arm64.bin"), sys._getframe().f_code.co_name, db_set, other_set], stdout = subprocess.PIPE).communicate()[0]
+        else:
+            if platform.machine() in ["AMD64", "x86_64"]:
+                data = subprocess.Popen([os.path.join(".", "route_go", "bin", "main.amd64.exe"), sys._getframe().f_code.co_name, db_set, other_set], stdout = subprocess.PIPE).communicate()[0]
+            else:
+                data = subprocess.Popen([os.path.join(".", "route_go", "bin", "main.arm64.exe"), sys._getframe().f_code.co_name, db_set, other_set], stdout = subprocess.PIPE).communicate()[0]
+
+        data = data.decode('utf8')
+
+        return flask.Response(response = data, status = 200, mimetype = 'application/json')

+ 5 - 5
route/go_api_func_sha224.py

@@ -4,15 +4,15 @@ def api_func_sha224(data = 'Test'):
     with get_db_connect() as conn:
         if platform.system() == 'Linux':
             if platform.machine() in ["AMD64", "x86_64"]:
-                data = subprocess.Popen([os.path.join(".", "route_go", "bin", sys._getframe().f_code.co_name + ".amd64.bin"), data], stdout = subprocess.PIPE).communicate()[0]
+                data = subprocess.Popen([os.path.join(".", "route_go", "bin", "main.amd64.bin"), sys._getframe().f_code.co_name, data], stdout = subprocess.PIPE).communicate()[0]
             else:
-                data = subprocess.Popen([os.path.join(".", "route_go", "bin", sys._getframe().f_code.co_name + ".arm64.bin"), data], stdout = subprocess.PIPE).communicate()[0]
+                data = subprocess.Popen([os.path.join(".", "route_go", "bin", "main.arm64.bin"), sys._getframe().f_code.co_name, data], stdout = subprocess.PIPE).communicate()[0]
         else:
             if platform.machine() in ["AMD64", "x86_64"]:
-                data = subprocess.Popen([os.path.join(".", "route_go", "bin", sys._getframe().f_code.co_name + ".amd64.exe"), data], stdout = subprocess.PIPE).communicate()[0]
+                data = subprocess.Popen([os.path.join(".", "route_go", "bin", "main.amd64.exe"), sys._getframe().f_code.co_name, data], stdout = subprocess.PIPE).communicate()[0]
             else:
-                data = subprocess.Popen([os.path.join(".", "route_go", "bin", sys._getframe().f_code.co_name + ".arm64.exe"), data], stdout = subprocess.PIPE).communicate()[0]
+                data = subprocess.Popen([os.path.join(".", "route_go", "bin", "main.arm64.exe"), sys._getframe().f_code.co_name, data], stdout = subprocess.PIPE).communicate()[0]
 
         data = data.decode('utf8')
 
-        return flask.jsonify({ "data" : data })
+        return flask.Response(response = data, status = 200, mimetype = 'application/json')

+ 25 - 0
route/go_api_recent_change.py

@@ -0,0 +1,25 @@
+from .tool.func import *
+
+def api_recent_change(db_set, num = 1, set_type = 'normal', limit = 10):
+    with get_db_connect() as conn:
+        other_set = {}
+        other_set["num"] = str(num)
+        other_set["limit"] = str(limit)
+        other_set["set_type"] = set_type
+        other_set["ip"] = ip_check()
+        other_set = json.dumps(other_set)
+
+        if platform.system() == 'Linux':
+            if platform.machine() in ["AMD64", "x86_64"]:
+                data = subprocess.Popen([os.path.join(".", "route_go", "bin", "main.amd64.bin"), sys._getframe().f_code.co_name, db_set, other_set], stdout = subprocess.PIPE).communicate()[0]
+            else:
+                data = subprocess.Popen([os.path.join(".", "route_go", "bin", "main.arm64.bin"), sys._getframe().f_code.co_name, db_set, other_set], stdout = subprocess.PIPE).communicate()[0]
+        else:
+            if platform.machine() in ["AMD64", "x86_64"]:
+                data = subprocess.Popen([os.path.join(".", "route_go", "bin", "main.amd64.exe"), sys._getframe().f_code.co_name, db_set, other_set], stdout = subprocess.PIPE).communicate()[0]
+            else:
+                data = subprocess.Popen([os.path.join(".", "route_go", "bin", "main.arm64.exe"), sys._getframe().f_code.co_name, db_set, other_set], stdout = subprocess.PIPE).communicate()[0]
+
+        data = data.decode('utf8')
+
+        return flask.Response(response = data, status = 200, mimetype = 'application/json')

+ 25 - 0
route/go_api_recent_edit_request.py

@@ -0,0 +1,25 @@
+from .tool.func import *
+
+def api_recent_edit_request(db_set, num = 1, set_type = 'normal', limit = 50):
+    with get_db_connect() as conn:
+        other_set = {}
+        other_set["num"] = str(num)
+        other_set["limit"] = str(limit)
+        other_set["set_type"] = set_type
+        other_set["ip"] = ip_check()
+        other_set = json.dumps(other_set)
+
+        if platform.system() == 'Linux':
+            if platform.machine() in ["AMD64", "x86_64"]:
+                data = subprocess.Popen([os.path.join(".", "route_go", "bin", "main.amd64.bin"), sys._getframe().f_code.co_name, db_set, other_set], stdout = subprocess.PIPE).communicate()[0]
+            else:
+                data = subprocess.Popen([os.path.join(".", "route_go", "bin", "main.arm64.bin"), sys._getframe().f_code.co_name, db_set, other_set], stdout = subprocess.PIPE).communicate()[0]
+        else:
+            if platform.machine() in ["AMD64", "x86_64"]:
+                data = subprocess.Popen([os.path.join(".", "route_go", "bin", "main.amd64.exe"), sys._getframe().f_code.co_name, db_set, other_set], stdout = subprocess.PIPE).communicate()[0]
+            else:
+                data = subprocess.Popen([os.path.join(".", "route_go", "bin", "main.arm64.exe"), sys._getframe().f_code.co_name, db_set, other_set], stdout = subprocess.PIPE).communicate()[0]
+
+        data = data.decode('utf8')
+
+        return flask.Response(response = data, status = 200, mimetype = 'application/json')

+ 24 - 0
route/go_api_search.py

@@ -0,0 +1,24 @@
+from .tool.func import *
+
+def api_search(db_set, name = 'Test', search_type = 'title', num = 1):
+    with get_db_connect() as conn:
+        other_set = {}
+        other_set["name"] = name
+        other_set["search_type"] = search_type
+        other_set["num"] = str(num)
+        other_set = json.dumps(other_set)
+
+        if platform.system() == 'Linux':
+            if platform.machine() in ["AMD64", "x86_64"]:
+                data = subprocess.Popen([os.path.join(".", "route_go", "bin", "main.amd64.bin"), sys._getframe().f_code.co_name, db_set, other_set], stdout = subprocess.PIPE).communicate()[0]
+            else:
+                data = subprocess.Popen([os.path.join(".", "route_go", "bin", "main.arm64.bin"), sys._getframe().f_code.co_name, db_set, other_set], stdout = subprocess.PIPE).communicate()[0]
+        else:
+            if platform.machine() in ["AMD64", "x86_64"]:
+                data = subprocess.Popen([os.path.join(".", "route_go", "bin", "main.amd64.exe"), sys._getframe().f_code.co_name, db_set, other_set], stdout = subprocess.PIPE).communicate()[0]
+            else:
+                data = subprocess.Popen([os.path.join(".", "route_go", "bin", "main.arm64.exe"), sys._getframe().f_code.co_name, db_set, other_set], stdout = subprocess.PIPE).communicate()[0]
+
+        data = data.decode('utf8')
+
+        return flask.Response(response = data, status = 200, mimetype = 'application/json')

+ 22 - 92
route/api_topic.py → route/go_api_topic.py

@@ -28,8 +28,9 @@ def api_topic_thread_make(user_id, date, data, code, color = '', blind = '', add
                     </td>
                 </tr>
                 <tr>
-                    <td class="''' + color_b + '''" id="opennamu_comment_data_main">
+                    <td class="''' + color_b + ''' opennamu_comment_data_main" id="thread_''' + code + '''">
                         ''' + data + '''
+                        <div id="opennamu_topic_req_''' + code + '''"></div>
                     </td>
                 </tr>
             </table>
@@ -118,103 +119,32 @@ def api_topic_thread_pre_render(curs, data, num, ip, topic_num = '', name = '',
 
     return data
 
-def api_topic(topic_num = 1, tool = 'normal', num = '', render = ''):
+def api_topic(db_set, topic_num = 1, tool = 'normal', s_num = '', e_num = ''):
     with get_db_connect() as conn:
-        curs = conn.cursor()
-
         topic_num = str(topic_num)
 
+        other_set = {}
+        other_set["topic_num"] = topic_num
+        other_set["tool"] = tool
+        other_set["s_num"] = str(s_num)
+        other_set["e_num"] = str(e_num)
+        other_set["ip"] = ip_check()
+        other_set = json.dumps(other_set)
+
         if acl_check('', 'topic_view', topic_num) != 1:
-            if tool == 'normal':
-                if num != '':
-                    curs.execute(db_change("select id, data, date, ip, block, top from topic where code = ? and id + 0 = ? + 0 order by id + 0 asc"), [topic_num, num])
+            if platform.system() == 'Linux':
+                if platform.machine() in ["AMD64", "x86_64"]:
+                    data = subprocess.Popen([os.path.join(".", "route_go", "bin", "main.amd64.bin"), sys._getframe().f_code.co_name, db_set, other_set], stdout = subprocess.PIPE).communicate()[0]
                 else:
-                    curs.execute(db_change("select id, data, date, ip, block, top from topic where code = ? order by id + 0 asc"), [topic_num])
-            elif tool == 'top':
-                curs.execute(db_change("select id, data, date, ip, block, top from topic where code = ? and top = 'O' order by id + 0 asc"), [topic_num])
+                    data = subprocess.Popen([os.path.join(".", "route_go", "bin", "main.arm64.bin"), sys._getframe().f_code.co_name, db_set, other_set], stdout = subprocess.PIPE).communicate()[0]
             else:
-                # tool == 'length'
-                curs.execute(db_change("select id from topic where code = ? order by id + 0 desc limit 1"), [topic_num])
-                db_data = curs.fetchall()
-                if db_data:
-                    return flask.jsonify({ 'length' : db_data[0][0] })
-                else:
-                    return flask.jsonify({})
-
-            data = curs.fetchall()
-            if data:
-                data_a = {}
-                admin = admin_check(3)
-
-                curs.execute(db_change("select ip from topic where code = ? order by id + 0 asc limit 1"), [topic_num])
-                data_f = curs.fetchall()
-                data_f = data_f[0][0] if data_f else ''
-                data_a['data_main'] = {
-                    "ip_first" : ip_pas(data_f, 1),
-                    "admin" : str(admin)
-                }
-                data_a['data'] = []
-
-                ip_a = ip_pas([i[3] for i in data])
-                ip_a_2 = ip_pas([i[3] for i in data], 1)
-                for i in data:
-                    data_v = i[1] if i[4] != 'O' or admin == 1 else ''
-                    if data_v != '':
-                        data_v = render_set(
-                            doc_data = data_v, 
-                            data_type = 'api_thread',
-                            data_in = 'topic_' + topic_num + '_' + i[0]
-                        )
-                    else:
-                        data_v = ['', '']
-
-                    data_a['data'] += [{
-                        "id" : i[0],
-
-                        "data" : data_v,
-                        "date" : i[2],
-                        "ip" : ip_a_2[i[3]],
-                        "blind" : i[4],
-
-                        "ip_pas" : ip_a[i[3]],
-                        "data_pas" : data_v
-                    }]
-
-                if render == '':
-                    return flask.jsonify(data_a)
+                if platform.machine() in ["AMD64", "x86_64"]:
+                    data = subprocess.Popen([os.path.join(".", "route_go", "bin", "main.amd64.exe"), sys._getframe().f_code.co_name, db_set, other_set], stdout = subprocess.PIPE).communicate()[0]
                 else:
-                    data_r = ''
-                    if 'data' in data_a:
-                        for for_a in data_a['data']:
-                            if tool == 'top':
-                                color = 'red'
-                            elif for_a["blind"] == '1':
-                                color = 'blue'
-                            elif data_a['data_main']["ip_first"] == for_a["ip"]:
-                                color = 'green'
-                            else:
-                                color = 'default'
-
-                            data_r += api_topic_thread_make(
-                                for_a["ip_pas"],
-                                '<a href="/thread/' + topic_num + '/comment/' + for_a["id"] + '/tool">(' + load_lang('tool') + ')</a> ' + for_a["date"],
-                                for_a["data_pas"][0] + '<script>' + for_a["data_pas"][1] + '</script>',
-                                for_a["id"],
-                                color = color,
-                                blind = for_a["blind"],
-                                add_style = '',
-                                admin_check = admin if tool == 'normal' else 0,
-                                topic_num = topic_num
-                            )
-
-                    if admin == 1 and tool == 'normal':
-                        data_r += '''
-                            <a href="javascript:opennamu_thread_blind();">(''' + load_lang('hide') + ''' | ''' + load_lang('hide_release') + ''')</a>
-                            <hr class="main_hr">
-                        '''
-
-                    return flask.jsonify({ "data" : data_r })
-            else:
-                return flask.jsonify({})
+                    data = subprocess.Popen([os.path.join(".", "route_go", "bin", "main.arm64.exe"), sys._getframe().f_code.co_name, db_set, other_set], stdout = subprocess.PIPE).communicate()[0]
+
+            data = data.decode('utf8')
+
+            return flask.Response(response = data, status = 200, mimetype = 'application/json')
         else:
             return flask.jsonify({})

+ 18 - 0
route/go_api_w_random.py

@@ -0,0 +1,18 @@
+from .tool.func import *
+
+def api_w_random(db_set):
+    with get_db_connect() as conn:
+        if platform.system() == 'Linux':
+            if platform.machine() in ["AMD64", "x86_64"]:
+                data = subprocess.Popen([os.path.join(".", "route_go", "bin", "main.amd64.bin"), sys._getframe().f_code.co_name, db_set], stdout = subprocess.PIPE).communicate()[0]
+            else:
+                data = subprocess.Popen([os.path.join(".", "route_go", "bin", "main.arm64.bin"), sys._getframe().f_code.co_name, db_set], stdout = subprocess.PIPE).communicate()[0]
+        else:
+            if platform.machine() in ["AMD64", "x86_64"]:
+                data = subprocess.Popen([os.path.join(".", "route_go", "bin", "main.amd64.exe"), sys._getframe().f_code.co_name, db_set], stdout = subprocess.PIPE).communicate()[0]
+            else:
+                data = subprocess.Popen([os.path.join(".", "route_go", "bin", "main.arm64.exe"), sys._getframe().f_code.co_name, db_set], stdout = subprocess.PIPE).communicate()[0]
+
+        data = data.decode('utf8')
+
+        return flask.Response(response = data, status = 200, mimetype = 'application/json')

+ 29 - 0
route/go_api_w_raw.py

@@ -0,0 +1,29 @@
+from .tool.func import *
+
+def api_w_raw(db_set, name = 'Test', rev = '', exist_check = ''):
+    with get_db_connect() as conn:
+        curs = conn.cursor()
+        
+        other_set = {}
+        other_set["name"] = name
+        other_set["rev"] = str(rev)
+        other_set["exist_check"] = exist_check
+        other_set = json.dumps(other_set)
+
+        if acl_check(name, 'render') != 1:
+            if platform.system() == 'Linux':
+                if platform.machine() in ["AMD64", "x86_64"]:
+                    data = subprocess.Popen([os.path.join(".", "route_go", "bin", "main.amd64.bin"), sys._getframe().f_code.co_name, db_set, other_set], stdout = subprocess.PIPE).communicate()[0]
+                else:
+                    data = subprocess.Popen([os.path.join(".", "route_go", "bin", "main.arm64.bin"), sys._getframe().f_code.co_name, db_set, other_set], stdout = subprocess.PIPE).communicate()[0]
+            else:
+                if platform.machine() in ["AMD64", "x86_64"]:
+                    data = subprocess.Popen([os.path.join(".", "route_go", "bin", "main.amd64.exe"), sys._getframe().f_code.co_name, db_set, other_set], stdout = subprocess.PIPE).communicate()[0]
+                else:
+                    data = subprocess.Popen([os.path.join(".", "route_go", "bin", "main.arm64.exe"), sys._getframe().f_code.co_name, db_set, other_set], stdout = subprocess.PIPE).communicate()[0]
+
+            data = data.decode('utf8')
+
+            return flask.Response(response = data, status = 200, mimetype = 'application/json')
+        else:
+            return flask.jsonify({})

+ 24 - 0
route/go_api_w_xref.py

@@ -0,0 +1,24 @@
+from .tool.func import *
+
+def api_w_xref(db_set, name = 'Test', page = 1, xref_type = '1'):
+    with get_db_connect() as conn:
+        other_set = {}
+        other_set["name"] = name
+        other_set["page"] = str(page)
+        other_set["do_type"] = xref_type
+        other_set = json.dumps(other_set)
+
+        if platform.system() == 'Linux':
+            if platform.machine() in ["AMD64", "x86_64"]:
+                data = subprocess.Popen([os.path.join(".", "route_go", "bin", "main.amd64.bin"), sys._getframe().f_code.co_name, db_set, other_set], stdout = subprocess.PIPE).communicate()[0]
+            else:
+                data = subprocess.Popen([os.path.join(".", "route_go", "bin", "main.arm64.bin"), sys._getframe().f_code.co_name, db_set, other_set], stdout = subprocess.PIPE).communicate()[0]
+        else:
+            if platform.machine() in ["AMD64", "x86_64"]:
+                data = subprocess.Popen([os.path.join(".", "route_go", "bin", "main.amd64.exe"), sys._getframe().f_code.co_name, db_set, other_set], stdout = subprocess.PIPE).communicate()[0]
+            else:
+                data = subprocess.Popen([os.path.join(".", "route_go", "bin", "main.arm64.exe"), sys._getframe().f_code.co_name, db_set, other_set], stdout = subprocess.PIPE).communicate()[0]
+
+        data = data.decode('utf8')
+
+        return flask.Response(response = data, status = 200, mimetype = 'application/json')

+ 4 - 4
route/go_main_func_easter_egg.py

@@ -13,14 +13,14 @@ def main_func_easter_egg():
     
         if platform.system() == 'Linux':
             if platform.machine() in ["AMD64", "x86_64"]:
-                data = subprocess.Popen([os.path.join(".", "route_go", "bin", sys._getframe().f_code.co_name + ".amd64.bin")], stdout = subprocess.PIPE).communicate()[0]
+                data = subprocess.Popen([os.path.join(".", "route_go", "bin", "main.amd64.bin"), sys._getframe().f_code.co_name], stdout = subprocess.PIPE).communicate()[0]
             else:
-                data = subprocess.Popen([os.path.join(".", "route_go", "bin", sys._getframe().f_code.co_name + ".arm64.bin")], stdout = subprocess.PIPE).communicate()[0]
+                data = subprocess.Popen([os.path.join(".", "route_go", "bin", "main.arm64.bin"), sys._getframe().f_code.co_name], stdout = subprocess.PIPE).communicate()[0]
         else:
             if platform.machine() in ["AMD64", "x86_64"]:
-                data = subprocess.Popen([os.path.join(".", "route_go", "bin", sys._getframe().f_code.co_name + ".amd64.exe")], stdout = subprocess.PIPE).communicate()[0]
+                data = subprocess.Popen([os.path.join(".", "route_go", "bin", "main.amd64.exe"), sys._getframe().f_code.co_name], stdout = subprocess.PIPE).communicate()[0]
             else:
-                data = subprocess.Popen([os.path.join(".", "route_go", "bin", sys._getframe().f_code.co_name + ".arm64.exe")], stdout = subprocess.PIPE).communicate()[0]
+                data = subprocess.Popen([os.path.join(".", "route_go", "bin", "main.arm64.exe"), sys._getframe().f_code.co_name], stdout = subprocess.PIPE).communicate()[0]
 
         data = data.decode('utf8')
 

+ 0 - 18
route/go_view_random.py

@@ -1,18 +0,0 @@
-from .tool.func import *
-
-def view_random(db_set):
-    with get_db_connect() as conn:
-        if platform.system() == 'Linux':
-            if platform.machine() in ["AMD64", "x86_64"]:
-                data = subprocess.Popen([os.path.join(".", "route_go", "bin", sys._getframe().f_code.co_name + ".amd64.bin"), db_set], stdout = subprocess.PIPE).communicate()[0]
-            else:
-                data = subprocess.Popen([os.path.join(".", "route_go", "bin", sys._getframe().f_code.co_name + ".arm64.bin"), db_set], stdout = subprocess.PIPE).communicate()[0]
-        else:
-            if platform.machine() in ["AMD64", "x86_64"]:
-                data = subprocess.Popen([os.path.join(".", "route_go", "bin", sys._getframe().f_code.co_name + ".amd64.exe"), db_set], stdout = subprocess.PIPE).communicate()[0]
-            else:
-                data = subprocess.Popen([os.path.join(".", "route_go", "bin", sys._getframe().f_code.co_name + ".arm64.exe"), db_set], stdout = subprocess.PIPE).communicate()[0]
-
-        data = data.decode('utf8')
-
-        return redirect('/w/' + url_pas(data))

+ 1 - 1
route/main_search.py

@@ -2,4 +2,4 @@ from .tool.func import *
 
 def main_search():
     with get_db_connect() as conn:
-        return redirect('/search/' + url_pas(flask.request.form.get('search', 'test')))
+        return redirect('/search/' + url_pas(flask.request.form.get('search', 'test')))

+ 12 - 16
route/main_search_deep.py

@@ -1,6 +1,8 @@
 from .tool.func import *
 
-def main_search_deep(name = 'Test', search_type = 'title', num = 1):
+from .go_api_search import api_search
+
+def main_search_deep(db_set, name = 'Test', search_type = 'title', num = 1):
     with get_db_connect() as conn:
         curs = conn.cursor()
 
@@ -11,9 +13,9 @@ def main_search_deep(name = 'Test', search_type = 'title', num = 1):
 
         if flask.request.method == 'POST':
             if search_type == 'title':
-                return redirect('/search/1/' + url_pas(flask.request.form.get('search', 'test')))
+                return redirect('/search_page/1/' + url_pas(flask.request.form.get('search', 'test')))
             else:
-                return redirect('/search_data/1/' + url_pas(flask.request.form.get('search', 'test')))
+                return redirect('/search_data_page/1/' + url_pas(flask.request.form.get('search', 'test')))
         else:
             div = '''
                 <form method="post">
@@ -24,9 +26,9 @@ def main_search_deep(name = 'Test', search_type = 'title', num = 1):
             '''
 
             if search_type == 'title':
-                div += '<a href="/search_data/1/' + url_pas(name) + '">(' + load_lang('search_document_data') + ')</a>'
+                div += '<a href="/search_data_page/1/' + url_pas(name) + '">(' + load_lang('search_document_data') + ')</a>'
             else:
-                div += '<a href="/search/1/' + url_pas(name) + '">(' + load_lang('search_document_name') + ')</a>'
+                div += '<a href="/search_page/1/' + url_pas(name) + '">(' + load_lang('search_document_name') + ')</a>'
 
             name_new = ''
             if re.search(r'^분류:', name):
@@ -37,7 +39,7 @@ def main_search_deep(name = 'Test', search_type = 'title', num = 1):
                 name_new = re.sub(r"^파일:", 'file:', name)
 
             if name_new != '':
-                div += ' <a href="/search/1/' + url_pas(name_new) + '">(' + name_new + ')</a>'
+                div += ' <a href="/search_page/1/' + url_pas(name_new) + '">(' + name_new + ')</a>'
 
             curs.execute(db_change("select title from data where title = ? collate nocase"), [name])
             link_id = '' if curs.fetchall() else 'class="opennamu_not_exist_link"'
@@ -48,25 +50,19 @@ def main_search_deep(name = 'Test', search_type = 'title', num = 1):
                         <a ''' + link_id + ' href="/w/' + url_pas(name) + '">' + html.escape(name) + '''</a>
                     </li>
                 </ul>
-                <hr class="main_hr">
                 <ul class="opennamu_ul">
             '''
 
-            if search_type == 'title':
-                curs.execute(db_change("select title from data where title like ? collate nocase order by title limit ?, 50"), ['%' + name + '%', sql_num])
-            else:
-                curs.execute(db_change("select title from data where data like ? collate nocase order by title limit ?, 50"), ['%' + name + '%', sql_num])
-
-            all_list = curs.fetchall()
+            all_list = json.loads(api_search(db_set, name, search_type, num).data)
             for data in all_list:
-                div += '<li><a href="/w/' + url_pas(data[0]) + '">' + data[0] + '</a></li>'
+                div += '<li><a href="/w/' + url_pas(data) + '">' + data + '</a></li>'
 
             div += '</ul>'
             
             if search_type == 'title':
-                div += get_next_page_bottom('/search/{}/' + url_pas(name), num, all_list)
+                div += get_next_page_bottom('/search_page/{}/' + url_pas(name), num, all_list)
             else:
-                div += get_next_page_bottom('/search_data/{}/' + url_pas(name), num, all_list)
+                div += get_next_page_bottom('/search_data_page/{}/' + url_pas(name), num, all_list)
 
             return easy_minify(flask.render_template(skin_check(),
                 imp = [name, wiki_set(), wiki_custom(), wiki_css(['(' + load_lang('search') + ')', 0])],

+ 5 - 1
route/main_setting_acl.py

@@ -17,7 +17,8 @@ def main_setting_acl():
             10 : 'slow_edit_acl',
             11 : 'edit_bottom_compulsion_acl',
             12 : 'recaptcha_pass_acl',
-            13 : 'recaptcha_one_check_five_pass_acl'
+            13 : 'recaptcha_one_check_five_pass_acl',
+            14 : 'document_edit_request_acl'
         }
         default_list = {
             12 : 'user'
@@ -66,6 +67,9 @@ def main_setting_acl():
                         <h3>''' + load_lang('document_edit_acl') + '''</h3>
                         <select ''' + disable + ''' name="document_edit_acl">''' + acl_div[6] + '''</select>
 
+                        <h3>''' + load_lang('document_edit_request_acl') + '''</h3>
+                        <select ''' + disable + ''' name="document_edit_request_acl">''' + acl_div[13] + '''</select>
+
                         <h3>''' + load_lang('document_move_acl') + '''</h3>
                         <select ''' + disable + ''' name="document_move_acl">''' + acl_div[7] + '''</select>
 

+ 8 - 5
route/main_sys_update.py

@@ -21,17 +21,20 @@ def main_sys_update():
             
             if platform.system() == 'Linux':
                 ok = []
-
                 ok += [os.system('git remote rm origin')]
                 ok += [os.system('git remote add origin https://github.com/opennamu/opennamu.git')]
-                ok += [os.system('git fetch origin ' + up_data)]
+                ok += [os.system('git fetch --depth=1 origin ' + up_data)]
                 ok += [os.system('git reset --hard origin/' + up_data)]
-                if (ok[0] and ok[1] and ok[2] and ok[3]) == 0:
-                    return redirect('/restart')
+                for for_a in ok[1:]:
+                    if for_a != 0:
+                        break
                 else:
-                    print('Error : update failed')
+                    return redirect('/restart')
+                
+                print('Error : update failed')
             elif platform.system() == 'Windows':
                 os.system('rd /s /q route')
+
                 urllib.request.urlretrieve('https://github.com/opennamu/opennamu/archive/' + up_data + '.zip', 'update.zip')
                 zipfile.ZipFile('update.zip').extractall('')
                 ok = os.system('xcopy /y /s /r opennamu-' + up_data + ' .')

+ 19 - 9
route/recent_change.py

@@ -37,7 +37,8 @@ def recent_change(name = '', tool = '', num = 1, set_type = 'normal'):
             ['move', load_lang('move')],
             ['delete', load_lang('delete')],
             ['revert', load_lang('revert')],
-            ['r1', load_lang('new_doc')]
+            ['r1', load_lang('new_doc')],
+            ['edit_request', load_lang('edit_request')]
         ]
 
         if flask.request.method == 'POST':
@@ -65,9 +66,9 @@ def recent_change(name = '', tool = '', num = 1, set_type = 'normal'):
 
                 set_type = '' if set_type == 'edit' else set_type
                 if set_type != 'normal':
-                    curs.execute(db_change('select id, title, date, ip, send, leng, hide from history where title = ? and type = ? order by id + 0 desc limit ?, 50'), [name, set_type, sql_num])
+                    curs.execute(db_change('select id, title, date, ip, send, leng, hide, type from history where title = ? and type = ? order by id + 0 desc limit ?, 50'), [name, set_type, sql_num])
                 else:
-                    curs.execute(db_change('select id, title, date, ip, send, leng, hide from history where title = ? order by id + 0 desc limit ?, 50'), [name, sql_num])
+                    curs.execute(db_change('select id, title, date, ip, send, leng, hide, type from history where title = ? order by id + 0 desc limit ?, 50'), [name, sql_num])
 
                 data_list = curs.fetchall()
             elif tool == 'record':
@@ -80,9 +81,9 @@ def recent_change(name = '', tool = '', num = 1, set_type = 'normal'):
                 set_type = '' if set_type == 'edit' else set_type
 
                 if set_type != 'normal':
-                    curs.execute(db_change('select id, title, date, ip, send, leng, hide from history where ip = ? and type = ? order by date desc limit ?, 50'), [name, set_type, sql_num])
+                    curs.execute(db_change('select id, title, date, ip, send, leng, hide, type from history where ip = ? and type = ? order by date desc limit ?, 50'), [name, set_type, sql_num])
                 else:
-                    curs.execute(db_change('select id, title, date, ip, send, leng, hide from history where ip = ? order by date desc limit ?, 50'), [name, sql_num])
+                    curs.execute(db_change('select id, title, date, ip, send, leng, hide, type from history where ip = ? order by date desc limit ?, 50'), [name, sql_num])
                 
                 data_list = curs.fetchall()
             else:
@@ -99,13 +100,13 @@ def recent_change(name = '', tool = '', num = 1, set_type = 'normal'):
                 if num == 1 or all_admin != 1:
                     curs.execute(db_change('select title, id from rc where type = ? order by date desc limit 50'), [set_type])
                     for for_a in curs.fetchall():
-                        curs.execute(db_change('select id, title, date, ip, send, leng, hide from history where title = ? and id = ?'), for_a)
+                        curs.execute(db_change('select id, title, date, ip, send, leng, hide, type from history where title = ? and id = ?'), for_a)
                         data_list += curs.fetchall()
                 else:
                     if set_type != 'normal':
-                        curs.execute(db_change('select id, title, date, ip, send, leng, hide from history where type = ? order by date desc limit ?, 50'), [set_type, sql_num])
+                        curs.execute(db_change('select id, title, date, ip, send, leng, hide, type from history where type = ? order by date desc limit ?, 50'), [set_type, sql_num])
                     else:
-                        curs.execute(db_change('select id, title, date, ip, send, leng, hide from history order by date desc limit ?, 50'), [sql_num])
+                        curs.execute(db_change('select id, title, date, ip, send, leng, hide, type from history order by date desc limit ?, 50'), [sql_num])
 
                     data_list = curs.fetchall()
 
@@ -129,6 +130,15 @@ def recent_change(name = '', tool = '', num = 1, set_type = 'normal'):
                 style = ['', '']
                 date = data[2]
 
+                type_data = ''
+                if data[7] != '':
+                    if data[7] == 'r1':
+                        type_data = ' (' + data[7] + ')'
+                    else:
+                        type_data = ' (' + load_lang(data[7]) + ')'
+
+                send += type_data
+
                 if data[6] == 'O':
                     if admin == 1:
                         style[0] = 'class="opennamu_history_blind"'
@@ -214,7 +224,7 @@ def recent_change(name = '', tool = '', num = 1, set_type = 'normal'):
                     '<hr class="main_hr">' + div + \
                 ''
 
-                menu = [['other', load_lang('return')]]
+                menu = [['other', load_lang('return')], ['recent_edit_request', load_lang('edit_request')]]
                 title = load_lang('recent_change')
 
                 if all_admin == 1:

+ 56 - 0
route/recent_edit_request.py

@@ -0,0 +1,56 @@
+from .tool.func import *
+
+from .recent_change import recent_change_send_render
+
+from .go_api_recent_edit_request import api_recent_edit_request
+
+def recent_edit_request(db_set):
+    with get_db_connect() as conn:
+        div = ''
+        div += '''
+            <table id="main_table_set">
+                <tbody>
+                    <tr id="main_table_top_tr">
+                        <td id="main_table_width">''' + load_lang('discussion_name') + '''</td>
+                        <td id="main_table_width">''' + load_lang('editor') + '''</td>
+                        <td id="main_table_width">''' + load_lang('time') + '''</td>
+                    </tr>
+        '''
+
+        all_list = json.loads(api_recent_edit_request(db_set).data)
+        for data in all_list:
+            if re.search(r"\+", data[5]):
+                leng = '<span style="color:green;">(' + data[5] + ')</span>'
+            elif re.search(r"\-", data[5]):
+                leng = '<span style="color:red;">(' + data[5] + ')</span>'
+            else:
+                leng = '<span style="color:gray;">(' + data[5] + ')</span>'
+
+            send = data[4]
+            ip = data[6]
+            date = data[2]
+
+            title = '<a href="/edit_request/' + url_pas(data[0]) + '">' + html.escape(data[0]) + '</a> '
+            title += '<a href="/history/' + url_pas(data[0]) + '">(r' + data[1] + ')</a> '
+
+            div += '''
+                <tr>
+                    <td>''' + title + ' ' + leng + '''</td>
+                    <td>''' + ip + '''</td>
+                    <td>''' + date + '''</td>
+                </tr>
+                <tr>
+                    <td colspan="3">''' + recent_change_send_render(html.escape(send)) + '''</td>
+                </tr>
+            '''
+
+        div += '' + \
+                '</tbody>' + \
+            '</table>' + \
+        ''
+
+        return easy_minify(flask.render_template(skin_check(),
+            imp = [load_lang('recent_edit_request'), wiki_set(), wiki_custom(), wiki_css([0, 0])],
+            data = div,
+            menu = [['recent_change', load_lang('return')]]
+        ))

+ 0 - 1
route/recent_history_add.py

@@ -24,7 +24,6 @@ def recent_history_add(name = 'Test', do_type = ''):
                 'Add:' + flask.request.form.get('get_ip', ''),
                 flask.request.form.get('send', ''),
                 leng,
-                t_check = 'add',
                 mode = 'add'
             )
 

+ 3 - 6
route/recent_history_tool.py

@@ -25,10 +25,7 @@ def recent_history_tool(name = 'Test', rev = 1):
         if admin_check(6) == 1:
             data += '<h3>' + load_lang('admin') + '</h3>'
             data += '<ul class="opennamu_ul">'
-            curs.execute(db_change('' + \
-                'select title from history ' + \
-                'where title = ? and id = ? and hide = "O"' + \
-            ''), [name, num])
+            curs.execute(db_change('select title from history where title = ? and id = ? and hide = "O"'), [name, num])
             data += '<li><a href="/history_hidden/' + num + '/' + url_pas(name) + '">'
             if curs.fetchall():
                 data += load_lang('hide_release') 
@@ -41,8 +38,8 @@ def recent_history_tool(name = 'Test', rev = 1):
         if admin_check() == 1:
             data += '<h3>' + load_lang('owner') + '</h3>'
             data += '<ul class="opennamu_ul">'
-            data += '<li><a href="/history_delete/' + num + '/' + url_pas(name) + '">' + load_lang('history_delete') + '</li>'
-            data += '<li><a href="/history_send/' + num + '/' + url_pas(name) + '">' + load_lang('send_edit') + '</li>'
+            data += '<li><a href="/history_delete/' + num + '/' + url_pas(name) + '">' + load_lang('history_delete') + '</a></li>'
+            data += '<li><a href="/history_send/' + num + '/' + url_pas(name) + '">' + load_lang('send_edit') + '</a></li>'
             data += '</ul>'
 
         return easy_minify(flask.render_template(skin_check(),

+ 158 - 159
route/tool/func.py

@@ -328,7 +328,6 @@ def get_db_table_list():
 
     # 폐지 예정 (user_set으로 통합)
     create_data['rb'] = ['block', 'end', 'today', 'blocker', 'why', 'band', 'login', 'ongoing']
-    create_data['scan'] = ['user', 'title', 'type']
 
     # 개편 예정 (wiki_set과 wiki_filter과 wiki_vote으로 변경)
     create_data['other'] = ['name', 'data', 'coverage']
@@ -595,6 +594,20 @@ def update(ver_num, set_data):
             curs.execute(db_change("update rb set ongoing = '' where ongoing is null"))
             curs.execute(db_change("update rb set login = '' where login is null"))
 
+        if ver_num < 3500375:
+            curs.execute(db_change("select title, type, user from scan"))
+            for for_a in curs.fetchall():
+                type_data = 'watchlist' if for_a[1] == '' else 'star_doc'
+                curs.execute(db_change("insert into user_set (id, name, data) values (?, ?, ?)"), [for_a[2], type_data, for_a[0]])
+
+        if ver_num < 3500376:
+            curs.execute(db_change("select doc_name, doc_rev from data_set where set_name = 'edit_request_data'"))
+            for for_a in curs.fetchall():
+                curs.execute(db_change("select id from history where title = ? order by id + 0 desc limit 1"), [for_a[0]])
+                get_data = curs.fetchall()
+                if get_data and (int(get_data[0][0]) + 1) == int(for_a[1]):
+                    curs.execute(db_change("insert into data_set (doc_name, doc_rev, set_name, set_data) values (?, ?, 'edit_request_doing', '1')"), [for_a[0], for_a[1]])
+
         conn.commit()
 
         print('Update completed')
@@ -752,7 +765,7 @@ def get_acl_list(type_d = 'normal'):
     if type_d == 'user':
         return ['', 'user', 'all']
     else:
-        return ['', 'all', 'user', 'admin', 'owner', '50_edit', 'email', 'ban', 'before', '30_day', 'ban_admin', 'not_all']
+        return ['', 'all', 'user', 'admin', 'owner', '50_edit', 'email', 'ban', 'before', '30_day', 'ban_admin', 'not_all', 'up_to_level_3', 'up_to_level_10']
 
 ## Func-simple-with_DB
 def get_user_title_list(ip = ''):
@@ -1045,7 +1058,7 @@ def wiki_css(data):
     data_css = ''
     data_css_dark = ''
 
-    data_css_ver = '196'
+    data_css_ver = '212'
     data_css_ver = '.cache_v' + data_css_ver
 
     if 'main_css' in global_wiki_set:
@@ -1053,6 +1066,12 @@ def wiki_css(data):
     else:
         data_css += '<meta http-equiv="Cache-Control" content="max-age=3600">'
 
+        # External JS
+        data_css += '<script src="https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.16.9/katex.min.js" integrity="sha512-LQNxIMR5rXv7o+b1l8+N1EZMfhG7iFZ9HhnbJkTp4zjNr5Wvst75AqUeFDxeRUa7l5vEDyUiAip//r+EFLLCyA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>'
+        data_css += '<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>'
+        data_css += '<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>'
+        data_css += '<script src="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.41.0/min/vs/loader.min.js" integrity="sha512-A+6SvPGkIN9Rf0mUXmW4xh7rDvALXf/f0VtOUiHlDUSPknu2kcfz1KzLpOJyL2pO+nZS13hhIjLqVgiQExLJrw==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>'
+
         # Func JS
         data_css += '<script src="/views/main_css/js/func/func.js' + data_css_ver + '"></script>'
         
@@ -1066,23 +1085,18 @@ def wiki_css(data):
         
         # Route JS
         data_css += '<script src="/views/main_css/js/route/editor.js' + data_css_ver + '"></script>'
-        data_css += '<script src="/views/main_css/js/route/editor_sub.js' + data_css_ver + '"></script>'
         data_css += '<script src="/views/main_css/js/route/render.js' + data_css_ver + '"></script>'
         data_css += '<script src="/views/main_css/js/route/topic.js' + data_css_ver + '"></script>'
-        data_css += '<script src="/views/main_css/js/route/topic_sub.js' + data_css_ver + '"></script>'
+        data_css += '<script src="/views/main_css/js/route/view.js' + data_css_ver + '"></script>'
         
         # Main CSS
         data_css += '<link rel="stylesheet" href="/views/main_css/css/main.css' + data_css_ver + '">'
 
-        # External
-        data_css += '<script src="https://cdn.jsdelivr.net/npm/katex@0.16.8/dist/katex.min.js" integrity="sha384-cpW21h6RZv/phavutF+AuVYrr+dA8xD9zs6FwLpaCct6O9ctzYFfFr4dgmgccOTx" crossorigin="anonymous"></script>'
-        data_css += '<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>'
-        data_css += '<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>'
-
         # External CSS
-        data_css += '<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.8/dist/katex.min.css" integrity="sha384-GvrOXuhMATgEsSwCs4smul74iXGOixntILdUW9XmUC6+HX0sLNAK3q71HotJqlAn" crossorigin="anonymous">'
+        data_css += '<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.16.9/katex.min.css" integrity="sha512-fHwaWebuwA7NSF5Qg/af4UeDx9XqUpYpOGgubo3yWu+b2IQR4UeQwbb42Ti7gVAjNtVoI/I9TEoYeu9omwcC6g==" crossorigin="anonymous" referrerpolicy="no-referrer" />'
         data_css += '<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" />'
-    
+        data_css += '<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.41.0/min/vs/editor/editor.main.min.css" integrity="sha512-MFDhxgOYIqLdcYTXw7en/n5BshKoduTitYmX8TkQ+iJOGjrWusRi8+KmfZOrgaDrCjZSotH2d1U1e/Z1KT6nWw==" crossorigin="anonymous" referrerpolicy="no-referrer" />'
+
         global_wiki_set['main_css'] = data_css
 
     # Darkmode
@@ -1315,140 +1329,106 @@ def load_skin(data = '', set_n = 0, default = 0):
     return skin_return_data
 
 # Func-markup
-def render_set(doc_name = '', doc_data = '', data_type = 'view', data_in = '', doc_acl = '', markup = ''):
+def render_set(doc_name = '', doc_data = '', data_type = 'view', markup = ''):
     with get_db_connect() as conn:
         curs = conn.cursor()
 
-        # data_type in ['view', 'from', 'thread', 'raw', 'api_view', 'api_thread', 'backlink']
+        # data_type in ['view', 'from', 'thread', 'api_view', 'api_thread', 'api_include', 'backlink']
         # data_type을 list 형식으로 개편 필요할 듯
-        if doc_name != '':
-            doc_acl = acl_check(doc_name, 'render') if doc_acl == '' else doc_acl
-        else:
-            doc_acl = 0
 
-        data_type = 'view' if data_type == '' else data_type
-        doc_data = 0 if doc_data == None else doc_data
+        return_type = True
+        if data_type in ['api_view', 'api_thread', 'api_include']:
+            return_type = False
+
+        if data_type == '':
+            data_type = 'view'
+        elif data_type == 'api_view':
+            data_type = 'view'
+        elif data_type == 'api_thread':
+            data_type = 'thread'
+        elif data_type == 'api_include':
+            data_type = 'include'
 
-        acl_dict = {}
-        acl_dict[doc_name] = doc_acl
+        doc_data = '' if doc_data == None else doc_data
 
         ip = ip_check()
-            
-        if doc_acl == 1:
-            return 'HTTP Request 401.3'
-        else:
-            if data_type == 'raw':
-                return doc_data
-            
-            if doc_data != 0:
-                render_lang_data = {
-                    'toc' : load_lang('toc'),
-                    'category' : load_lang('category')
-                }
+        render_lang_data = {
+            'toc' : load_lang('toc'),
+            'category' : load_lang('category')
+        }
 
-                curs.execute(db_change('select data from other where name = "category_text"'))
-                db_data = curs.fetchall()
-                if db_data and db_data[0][0] != '':
-                    render_lang_data['category'] = db_data[0][0]
+        curs.execute(db_change('select data from other where name = "category_text"'))
+        db_data = curs.fetchall()
+        if db_data and db_data[0][0] != '':
+            render_lang_data['category'] = db_data[0][0]
 
-                get_class_render = class_do_render(conn, render_lang_data, markup).do_render(doc_name, doc_data, data_type, data_in)
-                
-                if 'include' in get_class_render[2]:
-                    for_a = 0
-                    while len(get_class_render[2]['include']) > for_a:
-                        include_data = get_class_render[2]['include'][for_a]
-                        if include_data[1] in acl_dict:
-                            acl_result = acl_dict[include_data[1]]
-                        else:
-                            acl_result = acl_check(include_data[1], 'render')
-                            acl_dict[include_data[1]] = acl_result
-
-                        if acl_result == 0:
-                            include_regex = re.compile('<div id="' + include_data[0] + '"><\\/div>')
-                            if re.search(include_regex, get_class_render[0]):
-                                include_data_render = class_do_render(conn, render_lang_data, markup).do_render(include_data[1], include_data[2], data_type, include_data[0] + data_in)
-                                if len(include_data) > 3:
-                                    include_data_render[0] = '<div id="' + include_data[0] + '" ' + include_data[3] + '>' + include_data_render[0] + '</div>'
-                                else:
-                                    include_data_render[0] = '<div id="' + include_data[0] + '">' + include_data_render[0] + '</div>'
-
-                                get_class_render[0] = re.sub(include_regex, include_data_render[0], get_class_render[0])
-                                get_class_render[1] += include_data_render[1]
-                                get_class_render[2]['include'] += include_data_render[2]['include']
-
-                        for_a += 1
-
-                if data_type == 'backlink':
-                    return ''
-
-                get_class_render[0] = '<div class="opennamu_render_complete">' + get_class_render[0] + '</div>'
-
-                font_size_set_data = get_main_skin_set(curs, flask.session, 'main_css_font_size', ip)
-                if font_size_set_data != 'default':
-                    font_size_set_data = number_check(font_size_set_data)
-
-                    get_class_render[0] = '''
-                        <style>
-                            .opennamu_render_complete {
-                                font-size: ''' + font_size_set_data + '''px !important;
-                            }
-                        </style>
-                    ''' + get_class_render[0]
-
-                curs.execute(db_change("select data from other where name = 'namumark_compatible'"))
-                db_data = curs.fetchall()
-                if db_data and db_data[0][0] != '':
-                    get_class_render[0] = '''
-                        <style>
-                            .opennamu_render_complete {
-                                font-size: 15px !important;
-                                line-height: 1.5;
-                            }
-
-                            .opennamu_render_complete td {
-                                padding: 5px 10px !important;
-                            }
-
-                            .opennamu_render_complete summary {
-                                list-style: none !important;
-                                font-weight: bold !important;
-                            }
-                        </style>
-                    ''' + get_class_render[0]
-
-                table_set_data = get_main_skin_set(curs, flask.session, 'main_css_table_scroll', ip)
-                if table_set_data == 'on':
-                    get_class_render[0] = '<style>.table_safe { overflow-x: scroll; white-space: nowrap; }</style>' + get_class_render[0]
-
-                joke_set_data = get_main_skin_set(curs, flask.session, 'main_css_view_joke', ip)
-                if joke_set_data == 'off':
-                    get_class_render[0] = '<style>.opennamu_joke { display: none; }</style>' + get_class_render[0]
-
-                math_set_data = get_main_skin_set(curs, flask.session, 'main_css_math_scroll', ip)
-                if math_set_data == 'on':
-                    get_class_render[0] = '<style>.katex .base { overflow-x: scroll; }</style>' + get_class_render[0]
-
-                transparent_set_data = get_main_skin_set(curs, flask.session, 'main_css_table_transparent', ip)
-                if transparent_set_data == 'on':
-                    get_class_render[0] = '''
-                        <style>
-                            .table_safe td {
-                                background: transparent !important;
-                                color: inherit !important;
-                            }
-                        </style>
-                    ''' + get_class_render[0]
-
-                if data_type == 'api_view' or data_type == 'api_thread':
-                    return [
-                        get_class_render[0], 
-                        get_class_render[1]
-                    ]
-                else:
-                    return get_class_render[0] + '<script>' + get_class_render[1] + '</script>'
-            else:
-                return 'HTTP Request 404'
-            
+        get_class_render = class_do_render(conn, render_lang_data, markup).do_render(doc_name, doc_data, data_type)
+        if data_type == 'backlink':
+            return ''
+
+        get_class_render[0] = '<div class="opennamu_render_complete">' + get_class_render[0] + '</div>'
+
+        font_size_set_data = get_main_skin_set(curs, flask.session, 'main_css_font_size', ip)
+        if font_size_set_data != 'default':
+            font_size_set_data = number_check(font_size_set_data)
+
+            get_class_render[0] = '' + \
+                '''<style>
+                    .opennamu_render_complete {
+                        font-size: ''' + font_size_set_data + '''px !important;
+                    }
+                </style>''' + \
+            '' + get_class_render[0]
+
+        curs.execute(db_change("select data from other where name = 'namumark_compatible'"))
+        db_data = curs.fetchall()
+        if db_data and db_data[0][0] != '':
+            get_class_render[0] = '' + \
+                '''<style>
+                    .opennamu_render_complete {
+                        font-size: 15px !important;
+                        line-height: 1.5;
+                    }
+
+                    .opennamu_render_complete td {
+                        padding: 5px 10px !important;
+                    }
+
+                    .opennamu_render_complete summary {
+                        list-style: none !important;
+                        font-weight: bold !important;
+                    }
+                </style>''' + \
+            '' + get_class_render[0]
+
+        table_set_data = get_main_skin_set(curs, flask.session, 'main_css_table_scroll', ip)
+        if table_set_data == 'on':
+            get_class_render[0] = '<style>.table_safe { overflow-x: scroll; white-space: nowrap; }</style>' + get_class_render[0]
+
+        joke_set_data = get_main_skin_set(curs, flask.session, 'main_css_view_joke', ip)
+        if joke_set_data == 'off':
+            get_class_render[0] = '<style>.opennamu_joke { display: none; }</style>' + get_class_render[0]
+
+        math_set_data = get_main_skin_set(curs, flask.session, 'main_css_math_scroll', ip)
+        if math_set_data == 'on':
+            get_class_render[0] = '<style>.katex .base { overflow-x: scroll; }</style>' + get_class_render[0]
+
+        transparent_set_data = get_main_skin_set(curs, flask.session, 'main_css_table_transparent', ip)
+        if transparent_set_data == 'on':
+            get_class_render[0] = '' + \
+                '''<style>
+                    .table_safe td {
+                        background: transparent !important;
+                        color: inherit !important;
+                    }
+                </style>''' + \
+            '' + get_class_render[0]
+
+        if not return_type:
+            return [get_class_render[0], get_class_render[1]]
+        else:
+            return get_class_render[0] + '<script>' + get_class_render[1] + '</script>'
+        
 def render_simple_set(data):
     # without_DB
 
@@ -1836,14 +1816,20 @@ def admin_check(num = None, what = None, name = ''):
 
         return 0
 
-def acl_check(name = 'test', tool = '', topic_num = '1'):
+def acl_check(name = '', tool = '', topic_num = '1'):
     with get_db_connect() as conn:
         curs = conn.cursor()
 
+        if name == None:
+            name = ''
+
         ip = ip_check()
-        get_ban = ban_check()
+        if tool == 'document_edit_request':
+            get_ban = ban_check(ip, 'edit_request')
+        else:
+            get_ban = ban_check(ip)
         
-        if tool == '' and name:
+        if tool == '' and name != '':
             if acl_check(name, 'render') == 1:
                 return 1
             
@@ -1868,20 +1854,21 @@ def acl_check(name = 'test', tool = '', topic_num = '1'):
                     return 0
         
                 return 1
-        elif tool in ['document_edit', 'document_move', 'document_delete']:
+        elif tool in ['document_edit', 'document_edit_request', 'document_move', 'document_delete']:
             if acl_check(name, '') == 1:
                 return 1
         elif tool in ['bbs_edit', 'bbs_comment']:
             if acl_check(name, 'bbs_view') == 1:
                 return 1
         elif tool == 'topic':
-            curs.execute(db_change("select title from rd where code = ?"), [topic_num])
-            name = curs.fetchall()
-            name = name[0][0] if name else 'test'
+            if name == '':
+                curs.execute(db_change("select title from rd where code = ?"), [topic_num])
+                name = curs.fetchall()
+                name = name[0][0] if name else 'test'
 
         if tool in ['topic']:
             end = 3
-        elif tool in ['render', 'vote', '', 'document_edit', 'document_move', 'document_delete', 'document_edit', 'bbs_edit', 'bbs_comment']:
+        elif tool in ['render', 'vote', '', 'document_edit', 'document_edit_request', 'document_move', 'document_delete', 'document_edit', 'bbs_edit', 'bbs_comment']:
             end = 2
         else:
             end = 1
@@ -1982,6 +1969,13 @@ def acl_check(name = 'test', tool = '', topic_num = '1'):
                 curs.execute(db_change('select data from other where name = "recaptcha_one_check_five_pass_acl"'))
 
                 num = 'all'
+            elif tool == 'document_edit_request':
+                if i == 0:
+                    curs.execute(db_change("select data from acl where title = ? and type = 'document_edit_request_acl'"), [name])
+                else:
+                    curs.execute(db_change('select data from other where name = "document_edit_request_acl"'))
+
+                num = 5
             else:
                 # tool == 'render'
                 if i == 0:
@@ -2065,6 +2059,12 @@ def acl_check(name = 'test', tool = '', topic_num = '1'):
                         return 0
                 elif acl_data[0][0] == 'not_all':
                     return 1
+                elif acl_data[0][0] == 'up_to_level_3':
+                    if int(level_check(ip)[0]) >= 3:
+                        return 0
+                elif acl_data[0][0] == 'up_to_level_10':
+                    if int(level_check(ip)[0]) >= 10:
+                        return 0
 
                 return 1
             elif i == (end - 1):
@@ -2104,6 +2104,9 @@ def ban_check(ip = None, tool = ''):
                 if tool == 'login':
                     if test_r[0] != 'O':
                         return 1
+                elif tool == 'edit_request':
+                    if test_r[0][0] != 'E':
+                        return 1
                 else:
                     return 1
 
@@ -2113,6 +2116,9 @@ def ban_check(ip = None, tool = ''):
             if tool == 'login':
                 if ban_d[0][0] != 'O':
                     return 1
+            elif tool == 'edit_request':
+                if ban_d[0][0] != 'E':
+                    return 1
             else:
                 return 1
 
@@ -2157,18 +2163,9 @@ def ip_pas(raw_ip, type_data = 0):
             if is_this_ip != 0:
                 # ip user
                 if ip_view != '' and my_ip != raw_ip:
-                    try:
-                        ip = ipaddress.ip_address(raw_ip)
-                        if type(ip) == ipaddress.IPv6Address:
-                            ip = ip.exploded
-                            ip = re.sub(r':([^:]*):([^:]*)$', ':*:*', ip)
-                        else:
-                            ip = ip.exploded
-                            ip = re.sub(r'\.([^.]*)\.([^.]*)$', '.*.*', ip)
+                    ip = pw_encode(raw_ip)[:10]
 
-                        change_ip = 1
-                    except:
-                        ip = raw_ip
+                    change_ip = 1
                 else:
                     ip = raw_ip
             else:
@@ -2338,7 +2335,7 @@ def do_edit_filter(data):
                         ip,
                         r_time,
                         'edit filter',
-                        None,
+                        '',
                         'tool:edit filter'
                     )
 
@@ -2476,7 +2473,7 @@ def ban_insert(name, end, why, login, blocker, type_d = None, release = 0):
                 band
             ])
         else:
-            login = 'O' if login != '' else ''
+            login = login if login != '' else ''
             r_time = end if end != '0' else ''
 
             curs.execute(db_change("insert into rb (block, end, today, blocker, why, band, ongoing, login) values (?, ?, ?, ?, ?, ?, '1', ?)"), [
@@ -2519,7 +2516,7 @@ def history_plus(title, data, date, ip, send, leng, t_check = '', mode = ''):
             mode = 'r1' if id_data == '1' else mode
             mode = mode if not re.search('^user:', title) else 'user'
 
-        send = re.sub(r'\(|\)|<|>', '', send)
+        send = re.sub(r'<|>', '', send)
         send = send[:512] if len(send) > 512 else send
         send = send + ' (' + t_check + ')' if t_check != '' else send
 
@@ -2531,7 +2528,9 @@ def history_plus(title, data, date, ip, send, leng, t_check = '', mode = ''):
             history_plus_rc_max(curs, mode)
             curs.execute(db_change("insert into rc (id, title, date, type) values (?, ?, ?, ?)"), [id_data, title, date, mode])
 
-            data_set_exist = '' if t_check != 'delete' else 'not_exist'
+            data_set_exist = '' if mode != 'delete' else 'not_exist'
+
+            curs.execute(db_change('delete from data_set where doc_name = ? and set_name = "edit_request_doing"'), [title])
 
             curs.execute(db_change('delete from data_set where doc_name = ? and set_name = "last_edit"'), [title])
             curs.execute(db_change("insert into data_set (doc_name, doc_rev, set_name, set_data) values (?, '', 'last_edit', ?)"), [title, date])

+ 12 - 6
route/tool/func_render.py

@@ -17,18 +17,24 @@ class class_do_render:
         self.lang_data = lang_data
         self.markup = markup
 
-    def do_render(self, doc_name, doc_data, data_type, data_in):
+    def do_render(self, doc_name, doc_data, data_type):
         curs = self.conn.cursor()
 
         doc_set = {}
         if data_type == 'from':
             doc_set['doc_from'] = 'O'
             data_type = 'view'
+        else:
+            doc_set['doc_from'] = ''
+
+        if data_type == 'backlink':
+            doc_set['doc_type'] = 'view'
+        else:
+            doc_set['doc_type'] = data_type
         
-        data_in = (data_in + '_') if data_in != '' else ''
-        doc_set['doc_include'] = data_in
+        doc_set['doc_include'] = str(time.time_ns()) + '_'
+    
         rep_data = self.markup
-
         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()
@@ -47,7 +53,7 @@ class class_do_render:
         else:
             data_end = [doc_data, '', {}]
 
-        if data_type == 'thread' or data_type == 'api_thread':
+        if data_type == 'thread':
             def do_thread_a_change(match):
                 data = match[2].replace('#', '')
                 data_split = data.split('-')
@@ -63,7 +69,7 @@ class class_do_render:
             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' and data_in == '':
+        if data_type == 'backlink':
             curs.execute(db_change("delete from back where link = ?"), [doc_name])
             curs.execute(db_change("delete from back where title = ? and type = 'no'"), [doc_name])
 

+ 67 - 72
route/tool/func_render_namumark.py

@@ -7,7 +7,7 @@ class class_do_render_namumark:
         self.doc_data = doc_data.replace('\r', '')
         self.doc_name = doc_name
         self.doc_set = doc_set
-        self.doc_include = self.doc_set['doc_include'] if 'doc_include' in self.doc_set else ''
+
         self.do_type = do_type
 
         self.lang_data = lang_data
@@ -35,7 +35,6 @@ class class_do_render_namumark:
         self.data_temp_storage_count = 0
 
         self.data_backlink = {}
-        self.data_include = []
 
         self.data_math_count = 0
         self.data_redirect = 0
@@ -78,13 +77,13 @@ class class_do_render_namumark:
     def get_tool_data_storage(self, data_A = '', data_B = '', data_C = '', do_type = 'render'):        
         self.data_temp_storage_count += 1
         if do_type == 'render':
-            data_name = 'render_' + str(self.data_temp_storage_count) + '_' + self.doc_include
+            data_name = 'render_' + str(self.data_temp_storage_count) + '_' + self.doc_set['doc_include']
 
             self.data_temp_storage[data_name] = data_A
             self.data_temp_storage['/' + data_name] = data_B
             self.data_temp_storage['revert_' + data_name] = data_C
         else:
-            data_name = 'slash_' + str(self.data_temp_storage_count) + '_' + self.doc_include
+            data_name = 'slash_' + str(self.data_temp_storage_count) + '_' + self.doc_set['doc_include']
 
             self.data_temp_storage[data_name] = data_A
 
@@ -167,11 +166,11 @@ class class_do_render_namumark:
                 data += '(' + for_a + ') '
 
                 for for_b in self.data_footnote[for_a]['list']:
-                    data += '<sup><a id="' + self.doc_include + 'fn_' + for_b + '" href="#' + self.doc_include + 'rfn_' + for_b + '">(' + for_b + ')</a></sup> '
+                    data += '<sup><a id="' + self.doc_set['doc_include'] + 'fn_' + for_b + '" href="#' + self.doc_set['doc_include'] + 'rfn_' + for_b + '">(' + for_b + ')</a></sup> '
             else:
-                data += '<a id="' + self.doc_include + 'fn_' + self.data_footnote[for_a]['list'][0] + '" href="#' + self.doc_include + 'rfn_' + self.data_footnote[for_a]['list'][0] + '">(' + for_a + ') </a> '
+                data += '<a id="' + self.doc_set['doc_include'] + 'fn_' + self.data_footnote[for_a]['list'][0] + '" href="#' + self.doc_set['doc_include'] + 'rfn_' + self.data_footnote[for_a]['list'][0] + '">(' + for_a + ') </a> '
 
-            data += '<footnote_title id="' + self.doc_include + 'fn_' + self.data_footnote[for_a]['list'][0] + '_title">' + self.data_footnote[for_a]['data'] + '</footnote_title>'
+            data += '<footnote_title id="' + self.doc_set['doc_include'] + 'fn_' + self.data_footnote[for_a]['list'][0] + '_title">' + self.data_footnote[for_a]['data'] + '</footnote_title>'
 
         if data != '':
             data += '</div>'
@@ -231,7 +230,6 @@ class class_do_render_namumark:
         data_end = class_do_render_namumark(self.curs, self.doc_name, data, doc_set, self.lang_data, do_type = 'inter')()
 
         self.render_data_js += data_end[1]
-        self.data_include += data_end[2]['include']
         self.data_category_list += data_end[2]['category']
         self.data_backlink = dict(self.data_backlink, **data_end[2]['backlink_dict'])
         self.data_temp_storage = dict(self.data_temp_storage, **data_end[2]['temp_storage'][0])
@@ -384,11 +382,15 @@ class class_do_render_namumark:
                     if heading_data[2]:
                         heading_folding = ['⊕', 'none', '0.5']
 
+                    heading_id_name = 'edit_load_' + str(heading_count)
+                    if self.doc_set["doc_type"] != "view":
+                        heading_id_name = self.doc_set['doc_include'] + 'edit_load_' + str(heading_count)
+
                     data_name = self.get_tool_data_storage(
-                        '<h' + heading_level_str + '><span id="' + self.doc_include + 'opennamu_heading_' + str(heading_count) + '_sub" style="opacity: ' + heading_folding[2] + '">', 
+                        '<h' + heading_level_str + '><span id="' + self.doc_set['doc_include'] + 'opennamu_heading_' + str(heading_count) + '_sub" style="opacity: ' + heading_folding[2] + '">', 
                             ' <sub>' + \
-                                '<a id="' + self.doc_include + 'edit_load_' + str(heading_count) + '" href="/edit_section/' + str(heading_count) + '/' + url_pas(self.doc_name) + '">✎</a> ' + \
-                                '<a href="javascript:void(0);" onclick="javascript:opennamu_heading_folding(\'' + self.doc_include + 'opennamu_heading_' + str(heading_count) + '\', this);">' + \
+                                '<a id="' + heading_id_name + '" href="/edit_section/' + str(heading_count) + '/' + url_pas(self.doc_name) + '">✎</a> ' + \
+                                '<a href="javascript:void(0);" onclick="javascript:opennamu_heading_folding(\'' + self.doc_set['doc_include'] + 'opennamu_heading_' + str(heading_count) + '\', this);">' + \
                                     heading_folding[0] + \
                                 '</a>'
                             '</sub>' + \
@@ -405,7 +407,7 @@ class class_do_render_namumark:
                             '</heading_stack>' + \
                             ' ' + heading_data_text + \
                         '</' + data_name + '>' + \
-                        '<div id="' + self.doc_include + 'opennamu_heading_' + str(heading_count) + '" style="display: ' + heading_folding[1] + ';">' + \
+                        '<div id="' + self.doc_set['doc_include'] + 'opennamu_heading_' + str(heading_count) + '" style="display: ' + heading_folding[1] + ';">' + \
                         '<back_br>\n' + \
                     ''
 
@@ -481,15 +483,23 @@ class class_do_render_namumark:
 
             macro_split_regex = r'(?:^|,) *([^,]+)'
             macro_split_sub_regex = r'(^[^=]+) *= *([^=]+)'
-            if name_data in ('youtube', 'nicovideo', 'navertv', 'kakaotv', 'vimeo'):
+            if name_data in ('youtube', 'nicovideo', 'navertv', 'kakaotv', 'vimeo', 'instagram', 'twitter'):
                 data = re.findall(macro_split_regex, match[1])
 
                 # get option
                 video_code = ''
                 video_start = ''
                 video_end = ''
+                
                 video_width = '640px'
                 video_height = '360px'
+                if name_data == 'instagram':
+                    video_width = '360px'
+                    video_height = '480px'
+                elif name_data == 'twitter':
+                    video_width = '480px'
+                    video_height = '480px'
+
                 for for_a in data:
                     data_sub = re.search(macro_split_sub_regex, for_a)
                     if data_sub:
@@ -523,6 +533,12 @@ class class_do_render_namumark:
                     else:
                         if video_end != '':
                             video_code += '?end=' + video_end
+                elif name_data == 'instagram':
+                    video_code = re.sub(r'^https:\/\/www\.instagram\.com\/p\/', '', video_code)
+
+                    video_code = 'https://www.instagram.com/p/' + video_code +'/embed/'
+                elif name_data == 'twitter':
+                    video_code = 'https://twitframe.com/show?url=' + video_code
                 elif name_data == 'kakaotv':
                     video_code = re.sub(r'^https:\/\/tv\.kakao\.com\/v\/', '', video_code)
 
@@ -780,7 +796,7 @@ class class_do_render_namumark:
             data = html.unescape(data)
             data = self.get_tool_js_safe(data)
 
-            name_ob = self.doc_include + 'opennamu_math_' + str(self.data_math_count)
+            name_ob = self.doc_set['doc_include'] + 'opennamu_math_' + str(self.data_math_count)
 
             data_name = self.get_tool_data_storage('<span id="' + name_ob + '">' + data_html, '</span>', match.group(0))
 
@@ -1244,33 +1260,10 @@ class class_do_render_namumark:
         self.render_data = re.sub(r'(\\+)?@([ㄱ-힣a-zA-Z0-9]+)@', do_render_include_default_sub, self.render_data)
 
     def do_render_include(self):
-        def do_render_include_default_sub(match):
-            match_org = match.group(0)
-            match = match.groups()
-
-            if len(match) < 3:
-                match = list(match) + ['']
-
-            if match[2] == '\\':
-                return match_org
-            else:
-                slash_add = ''
-                if match[0]:
-                    if len(match[0]) % 2 == 1:
-                        slash_add = '\\' * (len(match[0]) - 1)
-                    else:
-                        slash_add = match[0]
-
-                if match[1] in include_change_list:
-                    return slash_add + include_change_list[match[1]]
-                else:
-                    return slash_add + match[2]
-
         include_num = 0
         include_set_data = get_main_skin_set(self.curs, self.flask_session, 'main_css_include_link', self.ip)
         include_regex = re.compile(r'\[include\(((?:(?!\[include\(|\)\]|<\/div>).)+)\)\](\n?)', re.I)
         include_count_max = len(re.findall(include_regex, self.render_data)) * 2
-        include_change_list = {}
         while 1:
             include_num += 1
             include_change_list = {}
@@ -1281,7 +1274,7 @@ class class_do_render_namumark:
             elif not match:
                 break
             else:
-                if re.search('opennamu_include_', self.doc_include):
+                if self.doc_set['doc_type'] == "include":
                     self.render_data = re.sub(include_regex, '', self.render_data, 1)
                 else:
                     match_org = match.group(0)
@@ -1320,28 +1313,21 @@ class class_do_render_namumark:
                     self.data_backlink[include_name]['include'] = ''
 
                     # load include db data
-                    self.curs.execute(db_change("select data from data where title = ?"), [include_name])
+                    self.curs.execute(db_change("select title from data where title = ?"), [include_name])
                     db_data = self.curs.fetchall()
                     if db_data:
-                        include_data = db_data[0][0].replace('\r', '')
-
                         # include link func
                         include_link = ''
                         if include_set_data == 'use':
                             include_link = '<div><a href="/w/' + url_pas(include_name) + '">(' + include_name_org + ')</a></div>'
 
-                        # parameter replace
-                        include_data = re.sub(r'(\\+)?@([ㄱ-힣a-zA-Z0-9]+)=((?:\\@|[^@\n])+)@', do_render_include_default_sub, include_data)
-                        include_data = re.sub(r'(\\+)?@([ㄱ-힣a-zA-Z0-9]+)@', do_render_include_default_sub, include_data)
-
-                        # remove end br
-                        include_data = re.sub('^\n+', '', include_data)
-
-                        self.data_include += [[self.doc_include + 'opennamu_include_' + str(include_num), self.doc_name, include_data, 'style="display: inline;"']]
-
+                        include_sub_name = self.doc_set['doc_include'] + 'opennamu_include_' + str(include_num)
+                        self.render_data_js += '''
+                            opennamu_do_include("''' + self.get_tool_js_safe(include_name) + '''", "''' + self.get_tool_js_safe(self.doc_name) + '''", "''' + self.get_tool_js_safe(include_sub_name) + '''", "''' + self.get_tool_js_safe(include_sub_name) + '''");\n
+                        '''
                         data_name = self.get_tool_data_storage('' + \
                             include_link + \
-                            '<div id="' + self.doc_include + 'opennamu_include_' + str(include_num) + '"></div>' + \
+                            '<div id="' + include_sub_name + '" style="display: none;">' + urllib.parse.quote(json.dumps(include_change_list)) + '</div>' + \
                         '', '', match_org)
                     else:
                         self.data_backlink[include_name]['no'] = ''
@@ -1405,8 +1391,8 @@ class class_do_render_namumark:
                             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
-                        rfn = self.doc_include + 'rfn_' + footnote_num_str
+                        fn = self.doc_set['doc_include'] + 'fn_' + footnote_first
+                        rfn = self.doc_set['doc_include'] + 'rfn_' + footnote_num_str
 
                         if footnote_number_set == 'only_number':
                             foot_v_name += footnote_first
@@ -1420,8 +1406,8 @@ class class_do_render_namumark:
                         self.data_footnote[footnote_name]['list'] = [footnote_num_str]
                         self.data_footnote[footnote_name]['data'] = footnote_text_data
 
-                        fn = self.doc_include + 'fn_' + footnote_num_str
-                        rfn = self.doc_include + 'rfn_' + footnote_num_str
+                        fn = self.doc_set['doc_include'] + 'fn_' + footnote_num_str
+                        rfn = self.doc_set['doc_include'] + 'rfn_' + footnote_num_str
 
                         if footnote_number_set == 'only_number':
                             foot_v_name += footnote_num_str
@@ -1476,7 +1462,7 @@ class class_do_render_namumark:
 
     def do_render_redirect(self):
         match = re.search(r'^<back_br>\n#(?:redirect|넘겨주기) ([^\n]+)', self.render_data, flags = re.I)
-        if match and self.doc_include == '':
+        if match and self.doc_set['doc_type'] == 'view':
             link_data_full = match.group(0)
             link_main = match.group(1)
 
@@ -1534,7 +1520,7 @@ class class_do_render_namumark:
 
                 self.data_redirect = 1
                 if link_exist == 1:
-                    if 'doc_from' in self.doc_set:
+                    if self.doc_set['doc_from'] != '':
                         data_name = self.get_tool_data_storage('<a href="' + link_main + link_data_sharp + '">(GO)</a>', '', link_data_full)
                     else:
                         data_name = self.get_tool_data_storage('<meta http-equiv="refresh" content="0; url=' + link_main + link_data_sharp + '">', '', link_data_full)
@@ -1614,7 +1600,7 @@ class class_do_render_namumark:
                     elif table_parameter_name == 'tableclass':
                         table_parameter_all['class'] = table_parameter_split[1]
                     elif table_parameter_name == 'tabletextalign':
-                        table_parameter_all['table'] += 'text-align:' + table_parameter_data + ';'
+                        table_parameter_all['table'] += 'text-align:' + table_parameter_data + ' !important;'
                     elif table_parameter_name == 'tablecolor':
                         table_parameter_all['table'] += 'color:' + self.get_tool_dark_mode_split(table_parameter_data) + ';'
                     elif table_parameter_name == 'tablebordercolor':
@@ -1622,13 +1608,15 @@ class class_do_render_namumark:
                     elif table_parameter_name == 'rowbgcolor':
                         table_parameter_all['tr'] += 'background:' + self.get_tool_dark_mode_split(table_parameter_data) + ';'
                     elif table_parameter_name == 'rowtextalign':
-                        table_parameter_all['tr'] += 'text-align:' + table_parameter_data + ';'
+                        table_parameter_all['tr'] += 'text-align:' + table_parameter_data + ' !important;'
                     elif table_parameter_name == 'rowcolor':
                         table_parameter_all['tr'] += 'color:' + self.get_tool_dark_mode_split(table_parameter_data) + ';'
                     elif table_parameter_name == 'colcolor':
                         table_parameter_all['col'] += 'color:' + self.get_tool_dark_mode_split(table_parameter_data) + ';'
                     elif table_parameter_name == 'colbgcolor':
                         table_parameter_all['col'] += 'background:' + self.get_tool_dark_mode_split(table_parameter_data) + ';'
+                    elif table_parameter_name == 'coltextalign':
+                        table_parameter_all['col'] += 'text-align:' + table_parameter_data + ' !important;'
                     elif table_parameter_name == 'bgcolor':
                         table_parameter_all['td'] += 'background:' + self.get_tool_dark_mode_split(table_parameter_data) + ';'
                     elif table_parameter_name == 'color':
@@ -1655,11 +1643,11 @@ class class_do_render_namumark:
                     elif table_parameter in ('(', ':', ')'):
                         table_align_auto = 0
                         if table_parameter == '(':
-                            table_parameter_all['td'] += 'text-align: left;'
+                            table_parameter_all['td'] += 'text-align: left !important;'
                         elif table_parameter == ':':
-                            table_parameter_all['td'] += 'text-align: center;'
+                            table_parameter_all['td'] += 'text-align: center !important;'
                         elif table_parameter == ')':
-                            table_parameter_all['td'] += 'text-align: right;'
+                            table_parameter_all['td'] += 'text-align: right !important;'
                     elif re.search(r'^(?:(?:#((?:[0-9a-f-A-F]{3}){1,2}))|(\w+))$', table_parameter):
                         table_parameter_data = self.get_tool_css_safe(table_parameter)
                         table_parameter_all['td'] += 'background:' + self.get_tool_dark_mode_split(table_parameter_data) + ';'
@@ -1678,6 +1666,7 @@ class class_do_render_namumark:
                     else:
                         table_parameter_all['td'] += 'text-align: right;'
                 else:
+                    table_parameter_all['td'] += 'text-align: left;'
                     if re.search(r' $', data):
                         data = re.sub(r' $', '', data)
 
@@ -1825,7 +1814,7 @@ class class_do_render_namumark:
                         wiki_data = self.get_tool_data_revert(wiki_data)
                         wiki_data = re.sub('(^\n|\n$)', '', wiki_data)
 
-                        middle_data_pass = self.do_inter_render(wiki_data, self.doc_include + 'opennamu_wiki_' + str(wiki_count))
+                        middle_data_pass = self.do_inter_render(wiki_data, self.doc_set['doc_include'] + 'opennamu_wiki_' + str(wiki_count))
 
                         data_name = self.get_tool_data_storage('<div ' + wiki_data_style + '>', '</div>', middle_data_org)
                         wiki_count += 1
@@ -1839,9 +1828,9 @@ class class_do_render_namumark:
                         data_revert = re.sub(r'\n$', '', data_revert)
                         data_revert = data_revert.replace('&amp;nbsp;', '&nbsp;')
 
-                        self.render_data_js += 'opennamu_do_render_html("' + self.doc_include + 'opennamu_wiki_' + str(html_count) + '");\n'
+                        self.render_data_js += 'opennamu_do_render_html("' + self.doc_set['doc_include'] + 'opennamu_wiki_' + str(html_count) + '");\n'
 
-                        data_name = self.get_tool_data_storage('<span id="' + self.doc_include + 'opennamu_wiki_' + str(html_count) + '">' + data_revert, '</span>', middle_data_org)
+                        data_name = self.get_tool_data_storage('<span id="' + self.doc_set['doc_include'] + 'opennamu_wiki_' + str(html_count) + '">' + data_revert, '</span>', middle_data_org)
                         html_count += 1
                     elif middle_name == '#!folding':
                         if middle_slash:
@@ -1862,7 +1851,7 @@ class class_do_render_namumark:
                         wiki_data = self.get_tool_data_revert(wiki_data)
                         wiki_data = re.sub('(^\n|\n$)', '', wiki_data)
 
-                        wiki_data_end = self.do_inter_render(wiki_data, self.doc_include + 'opennamu_folding_' + str(folding_count))
+                        wiki_data_end = self.do_inter_render(wiki_data, self.doc_set['doc_include'] + 'opennamu_folding_' + str(folding_count))
 
                         middle_data_pass = wiki_data_folding
                         data_name = self.get_tool_data_storage('<details><summary>', '</summary><div class="opennamu_folding">', middle_data_org)
@@ -2058,7 +2047,7 @@ class class_do_render_namumark:
                 quote_data = re.sub(r'\n$', '', quote_data)
                 quote_data = self.get_tool_data_revert(quote_data)
 
-                quote_data_end = self.do_inter_render(quote_data, self.doc_include + 'opennamu_quote_' + str(quote_count))
+                quote_data_end = self.do_inter_render(quote_data, self.doc_set['doc_include'] + 'opennamu_quote_' + str(quote_count))
                 data_name = self.get_tool_data_storage('<div>', '</div>', quote_data_org)
 
                 self.render_data = re.sub(quote_regex, lambda x : ('\n<blockquote><back_br>\n<' + data_name + '>' + quote_data_end + '</' + data_name + '><front_br></blockquote>\n'), self.render_data, 1)
@@ -2175,7 +2164,6 @@ class class_do_render_namumark:
 
                     return '<li style="margin-left: ' + str((list_len - 1) * 20) + 'px;" class="opennamu_list_none">' + change_text + '. ' + list_data + '</li>'
 
-        # 숫자 리스트
         list_regex = r'((?:\n( *)(?:(\*)) ?([^\n]*))+|(?:\n( *)(?:(1|a|A|I|i)\.(?:#([0-9]*))?) ?([^\n]*)){2,})\n'
         list_count_max = len(re.findall(list_regex, self.render_data)) * 3
         while 1:
@@ -2203,7 +2191,7 @@ class class_do_render_namumark:
         self.render_data = self.render_data.replace('<no_td>', '||')
 
         # add category
-        if self.doc_include == '':
+        if self.doc_set["doc_type"] == 'view':
             if self.data_category != '':
                 data_name = self.get_tool_data_storage(self.data_category, '</div>', '')
 
@@ -2304,7 +2292,7 @@ class class_do_render_namumark:
                 self.render_data = self.render_data.replace('<toc_need_part>', self.data_toc, 20)
                 self.render_data = self.render_data.replace('<toc_need_part>', '')
 
-            if self.doc_include != '' or re.search(r'<toc_no_auto>', self.render_data) or toc_set_data == 'half_off' or toc_set_data == 'off' or toc_data_on == 1:
+            if self.doc_set["doc_type"] != 'view' or re.search(r'<toc_no_auto>', self.render_data) or toc_set_data == 'half_off' or toc_set_data == 'off' or toc_data_on == 1:
                 self.render_data = self.render_data.replace('<toc_no_auto>', '')
             else:
                 self.render_data = re.sub(r'(?P<in><h[1-6] id="[^"]*">)', '<br>' + self.data_toc + '\\g<in>', self.render_data, 1)
@@ -2327,6 +2315,15 @@ class class_do_render_namumark:
 
         self.render_data = re.sub(r'<a fn_target="([^"]+)"', do_render_last_footnote, self.render_data)
 
+        self.render_data_js += '''
+            document.querySelectorAll('details').forEach((el) => {
+                new Accordion(el);
+            });
+            if(window.location.hash !== '' && document.getElementById(window.location.hash.replace(/^#/, ''))) {
+                document.getElementById(window.location.hash.replace(/^#/, '')).focus();
+            }\n
+        '''
+
     def __call__(self):
         self.do_render_remark()
         self.do_render_include_default()
@@ -2352,7 +2349,6 @@ class class_do_render_namumark:
             
         if self.do_type == 'exter':
             self.do_render_last()
-            self.data_include = list(reversed(self.data_include))
         else:
             self.render_data = self.render_data.replace(r'\|\|', '<no_td>')
             self.render_data = self.render_data.replace('\n', '<no_br>')
@@ -2367,7 +2363,6 @@ class class_do_render_namumark:
             {
                 'backlink' : self.data_backlink, # backlink
                 'backlink_dict' : data_backlink_dict,
-                'include' : self.data_include, # include data
                 'footnote' : self.data_footnote_all, # footnote
                 'category' : self.data_category_list,
                 'temp_storage' : [self.data_temp_storage, self.data_temp_storage_count],

+ 1 - 0
route/tool/func_tool.py

@@ -7,6 +7,7 @@ import re
 
 import os
 import html
+import time
 import json
 import threading
 

+ 31 - 35
route/topic.py

@@ -1,6 +1,6 @@
 from .tool.func import *
 
-from .api_topic import api_topic, api_topic_thread_pre_render
+from .go_api_topic import api_topic_thread_pre_render
 
 from .edit import edit_editor
 
@@ -9,7 +9,25 @@ def topic(topic_num = 0, do_type = '', doc_name = 'Test'):
         curs = conn.cursor()
         topic_num = str(topic_num)
 
-        topic_acl = acl_check('', 'topic', topic_num)
+        if topic_num == '0':
+            name = load_lang('make_new_topic')
+            sub = load_lang('make_new_topic')
+
+            name_value = doc_name
+            sub_value = ''
+        else:
+            curs.execute(db_change("select title, sub from rd where code = ?"), [topic_num])
+            name = curs.fetchall()
+            if name:
+                sub = name[0][1]
+                name = name[0][0]
+
+                name_value = name
+                sub_value = sub
+            else:
+                return redirect('/')
+                
+        topic_acl = acl_check(name_value, 'topic', topic_num)
         topic_view_acl = acl_check('', 'topic_view', topic_num)
         if topic_view_acl == 1:
             return re_error('/ban')
@@ -99,26 +117,6 @@ def topic(topic_num = 0, do_type = '', doc_name = 'Test'):
 
             return redirect('/thread/' + topic_num + '#' + num)
         else:
-            thread_data = ''
-
-            if topic_num == '0':
-                name = load_lang('make_new_topic')
-                sub = load_lang('make_new_topic')
-
-                name_value = doc_name
-                sub_value = ''
-            else:
-                curs.execute(db_change("select title, sub from rd where code = ?"), [topic_num])
-                name = curs.fetchall()
-                if name:
-                    sub = name[0][1]
-                    name = name[0][0]
-
-                    name_value = name
-                    sub_value = sub
-                else:
-                    return redirect('/')
-
             acl_display = 'display: none;' if topic_acl == 1 else ''
             name_display = 'display: none;' if topic_num != '0' else ''
 
@@ -130,14 +128,6 @@ def topic(topic_num = 0, do_type = '', doc_name = 'Test'):
             
             shortcut += '</div>'
 
-            top_topic = ''
-            json_data = json.loads(api_topic(int(topic_num), 'top', '', 'render').data)
-            top_topic += json_data['data'] if 'data' in json_data else ''
-            
-            main_topic = ''
-            json_data = json.loads(api_topic(int(topic_num), 'normal', '', 'render').data)
-            main_topic += json_data['data'] if 'data' in json_data else ''
-
             return easy_minify(flask.render_template(skin_check(),
                 imp = [name, wiki_set(), wiki_custom(), wiki_css(['(' + load_lang('discussion') + ')', 0])],
                 data = '''
@@ -147,14 +137,20 @@ def topic(topic_num = 0, do_type = '', doc_name = 'Test'):
                         }
                     </style>
                     <input type="checkbox" onclick="opennamu_do_remove_blind_thread();" checked> ''' + load_lang('remove_blind_thread') + '''
+                    <hr class="main_hr">
 
                     ''' + shortcut + '''
                     <h2 id="topic_top_title">''' + html.escape(sub) + '''</h2>
                     
-                    <div id="top_topic">''' + top_topic + '''</div>
-                    <div id="main_topic">''' + main_topic + '''</div>
-                    <div id="plus_topic"></div>
-                    
+                    <div id="opennamu_top_thread"></div>
+                    <div id="opennamu_main_thread"></div>
+                    <div id="opennamu_reload_thread"></div>
+                    <script>
+                        opennamu_get_thread("''' + topic_num + '''", "top");
+                        opennamu_get_thread("''' + topic_num + '''");
+                    </script>
+
+                    <a href="javascript:opennamu_thread_blind();">(''' + load_lang('hide') + ''' | ''' + load_lang('hide_release') + ''')</a>
                     <a href="/thread/''' + topic_num + '/tool">(' + load_lang('topic_tool') + ''')</a>
                     <hr class="main_hr">
                     
@@ -166,7 +162,7 @@ def topic(topic_num = 0, do_type = '', doc_name = 'Test'):
                             <hr class="main_hr">
                         </div>
                         
-                        ''' + edit_editor(curs, ip, thread_data, 'thread') + '''
+                        ''' + edit_editor(curs, ip, '', 'thread') + '''
                     </form>
                 ''',
                 menu = [['topic/' + url_pas(name), load_lang('list')]]

+ 0 - 13
route/topic_list.py

@@ -1,7 +1,5 @@
 from .tool.func import *
 
-from .api_topic import api_topic
-
 def topic_list(name = 'Test'):
     with get_db_connect() as conn:
         curs = conn.cursor()
@@ -34,19 +32,8 @@ def topic_list(name = 'Test'):
             curs.execute(db_change("select code, sub from rd where title = ? and stop != 'O' order by date desc"), [name])
 
         for data in curs.fetchall():
-            curs.execute(db_change("select id from topic where code = ? order by id + 0 desc limit 1"), [data[0]])
-            db_data = curs.fetchall()
-            last_thread = db_data[0][0] if db_data else '1'
-
             div += '<h2><a href="/thread/' + data[0] + '">' + data[0] + '. ' + html.escape(data[1]) + '</a></h2>'
 
-            first_data = json.loads(api_topic(data[0], 'normal', 1, 'render').data)
-            div += first_data['data'] if 'data' in first_data else ''
-
-            if last_thread != '1':
-                last_data = json.loads(api_topic(data[0], 'normal', int(last_thread), 'render').data)
-                div += last_data['data'] if 'data' in last_data else ''
-
         if div == '':
             plus = re.sub(r'^<br>', '', plus)
 

+ 6 - 14
route/user_watch_list.py

@@ -15,26 +15,18 @@ def user_watch_list(tool):
             return redirect('/login')
 
         if tool == 'watch_list':
-            curs.execute(db_change("select title from scan where type = '' and user = ?"), [ip])
-
+            curs.execute(db_change("select data from user_set where name = 'watchlist' and id = ?"), [ip])
             title_name = load_lang('watchlist')
         else:
-            curs.execute(db_change("select title from scan where type = 'star' and user = ?"), [ip])
-
+            curs.execute(db_change("select data from user_set where name = 'star_doc' and id = ?"), [ip])
             title_name = load_lang('star_doc')
 
         data = curs.fetchall()
         for data_list in data:
-            if tool == 'star_doc':
-                curs.execute(db_change("select date from history where title = ? order by id + 0 desc limit 1"), [data_list[0]])
-                get_data = curs.fetchall()
-                if get_data:
-                    plus = '(' + get_data[0][0] + ') '
-                else:
-                    plus = ''
-            else:
-                plus = ''
-
+            curs.execute(db_change("select date from history where title = ? order by id + 0 desc limit 1"), [data_list[0]])
+            get_data = curs.fetchall()
+            plus = '(' + get_data[0][0] + ') ' if get_data else ''
+            
             div += '' + \
                 '<li>' + \
                     '<a href="/w/' + url_pas(data_list[0]) + '">' + html.escape(data_list[0]) + '</a> ' + \

+ 25 - 13
route/user_watch_list_name.py

@@ -7,26 +7,38 @@ def user_watch_list_name(tool, name = 'Test'):
         ip = ip_check()
         if ip_or_user(ip) != 0:
             return redirect('/login')
+        
+        name_from = 0
+        if tool == 'watch_list_from':
+            name_from = 1
+            tool = 'watch_list'
+        elif tool == 'star_doc_from':
+            name_from = 1
+            tool = 'star_doc'
 
         if tool == 'watch_list':
-            curs.execute(db_change("select count(*) from scan where user = ?"), [ip])
-            count = curs.fetchall()
-            if count and count[0][0] > 9:
-                return re_error('/error/28')
-
-            type_data = ''
+            type_data = 'watchlist'
         else:
-            type_data = 'star'
+            type_data = 'star_doc'
 
-        curs.execute(db_change("select title from scan where user = ? and title = ? and type = ?"), [ip, name, type_data])
+        curs.execute(db_change("select data from user_set where name = ? and id = ? and data = ?"), [type_data, ip, name])
         if curs.fetchall():
-            curs.execute(db_change("delete from scan where user = ? and title = ? and type = ?"), [ip, name, type_data])
+            curs.execute(db_change("delete from user_set where name = ? and id = ? and data = ?"), [type_data, ip, name])
         else:
-            curs.execute(db_change("insert into scan (user, title, type) values (?, ?, ?)"), [ip, name, type_data])
+            if tool == 'watch_list':
+                curs.execute(db_change("select count(*) from user_set where id = ? and name = ?"), [ip, type_data])
+                count = curs.fetchall()
+                if count and count[0][0] > 10:
+                    return re_error('/error/28')
+
+            curs.execute(db_change("insert into user_set (id, name, data) values (?, ?, ?)"), [ip, type_data, name])
 
         conn.commit()
 
-        if tool == 'watch_list':
-            return redirect('/watch_list')
+        if name_from == 1:
+            return redirect('/w/' + url_pas(name))
         else:
-            return redirect('/star_doc')
+            if tool == 'watch_list':
+                return redirect('/watch_list')
+            else:
+                return redirect('/star_doc')

+ 64 - 60
route/view_diff.py

@@ -1,5 +1,67 @@
 from .tool.func import *
 
+def view_diff_do(first_raw_data, second_raw_data, first, second):
+    if first_raw_data == second_raw_data:
+        result = ''
+    else:
+        diff_data = diff_match_patch().diff_main(first_raw_data, second_raw_data)
+        diff_data += [[0, '\n']]
+        
+        diff_data_2 = []
+        temp_list = []
+        line = 1
+        line_change = 0
+        for for_a in diff_data:
+            line_split = re.findall(r'(.*\n)|(.+$)', for_a[1])
+            if line_split:
+                for for_b in line_split:
+                    if for_b[0] != '':
+                        if for_a[0] != 0:
+                            line_change = 1
+                        
+                        temp_list += [[line, for_a[0], for_b[0].replace('\n', '')]]
+
+                        if line_change == 1:
+                            diff_data_2 += temp_list
+                        
+                        temp_list = []
+                        line_change = 0
+                        line += 1
+                    else:
+                        if for_a[0] != 0:
+                            line_change = 1
+
+                        temp_list += [[line, for_a[0], for_b[1]]]
+            else:
+                if for_a[0] != 0:
+                    line_change = 1
+
+                temp_list += [[line, for_a[0], for_a[1]]]
+
+        result = '<table style="width: 100%; white-space: pre-wrap;"><tr><td colspan="2">' + first + ' ➤ ' + second + '</td></tr>'
+        result += '<tr><td style="width: 40px; user-select: none;">'
+
+        line = 0
+        for for_a in diff_data_2:
+            if line == 0:
+                line = for_a[0]
+                result += str(line) + '</td><td>'
+            else:
+                if line != for_a[0]:
+                    line = for_a[0]
+                    result += '</td></tr><tr><td style="width: 40px; user-select: none;">' + str(line) + '</td><td>'
+
+            if for_a[1] == 1:
+                result += '<span class="opennamu_diff_green">' + html.escape(for_a[2]) + '</span>'
+            elif for_a[1] == 0:
+                result += html.escape(for_a[2])
+            else:
+                result += '<span class="opennamu_diff_red">' + html.escape(for_a[2]) + '</span>'
+
+        result += '</td></tr></table>'
+
+    return result
+
 def view_diff(name = 'Test', num_a = 1, num_b = 1):
     with get_db_connect() as conn:
         curs = conn.cursor()
@@ -19,70 +81,12 @@ def view_diff(name = 'Test', num_a = 1, num_b = 1):
 
         curs.execute(db_change("select data from history where id = ? and title = ?"), [second, name])
         second_raw_data = curs.fetchall()
+        
         if first_raw_data and second_raw_data:
             first_raw_data = first_raw_data[0][0].replace('\r', '')
             second_raw_data = second_raw_data[0][0].replace('\r', '')
 
-            if first_raw_data == second_raw_data:
-                result = ''
-            else:
-                diff_data = diff_match_patch().diff_main(first_raw_data, second_raw_data)
-                diff_data += [[0, '\n']]
-                
-                diff_data_2 = []
-                temp_list = []
-                line = 1
-                line_change = 0
-                for for_a in diff_data:
-                    line_split = re.findall(r'(.*\n)|(.+$)', for_a[1])
-                    if line_split:
-                        for for_b in line_split:
-                            if for_b[0] != '':
-                                if for_a[0] != 0:
-                                    line_change = 1
-                                
-                                temp_list += [[line, for_a[0], for_b[0].replace('\n', '')]]
-
-                                if line_change == 1:
-                                    diff_data_2 += temp_list
-                                
-                                temp_list = []
-                                line_change = 0
-                                line += 1
-                            else:
-                                if for_a[0] != 0:
-                                    line_change = 1
-
-                                temp_list += [[line, for_a[0], for_b[1]]]
-                    else:
-                        if for_a[0] != 0:
-                            line_change = 1
-
-                        temp_list += [[line, for_a[0], for_a[1]]]
-
-                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;">'
-
-                # 개행만 추가된 경우 조정 필요
-                
-                line = 0
-                for for_a in diff_data_2:
-                    if line == 0:
-                        line = for_a[0]
-                        result += str(line) + '</td><td>'
-                    else:
-                        if line != for_a[0]:
-                            line = for_a[0]
-                            result += '</td></tr><tr><td style="width: 40px; user-select: none;">' + str(line) + '</td><td>'
-
-                    if for_a[1] == 1:
-                        result += '<span class="opennamu_diff_green">' + html.escape(for_a[2]) + '</span>'
-                    elif for_a[1] == 0:
-                        result += html.escape(for_a[2])
-                    else:
-                        result += '<span class="opennamu_diff_red">' + html.escape(for_a[2]) + '</span>'
-
-                result += '</td></tr></table>'
+            result = view_diff_do(first_raw_data, second_raw_data, 'r' + first, 'r' + second)
 
             return easy_minify(flask.render_template(skin_check(),
                 imp = [name, wiki_set(), wiki_custom(), wiki_css(['(' + load_lang('compare') + ')', 0])],

+ 9 - 0
route/view_random.py

@@ -0,0 +1,9 @@
+from .tool.func import *
+
+from .go_api_w_random import api_w_random
+
+def view_random(db_set):
+    with get_db_connect() as conn:
+        data = json.loads(api_w_random(db_set).data)["data"]
+        
+        return redirect('/w/' + url_pas(data))

+ 19 - 6
route/view_raw.py

@@ -3,7 +3,7 @@ from .tool.func import *
 from .api_bbs_w_post import api_bbs_w_post
 from .api_bbs_w_comment_one import api_bbs_w_comment_one
 
-def view_raw_2(name = None, topic_num = None, num = None, doc_acl = 0, bbs_num = '', post_num = '', comment_num = ''):
+def view_raw(name = '', topic_num = '', num = '', doc_acl = 0, bbs_num = '', post_num = '', comment_num = ''):
     with get_db_connect() as conn:
         curs = conn.cursor()
         
@@ -12,10 +12,10 @@ def view_raw_2(name = None, topic_num = None, num = None, doc_acl = 0, bbs_num =
 
         if bbs_num != '' and post_num != '':
             if acl_check(bbs_num_str, 'bbs_view') == 1:
-                    return re_error('/ban')
+                return re_error('/ban')
                     
             name = ''
-        elif topic_num:
+        elif topic_num != '':
             topic_num = str(topic_num)
             
             if acl_check('', 'topic_view', topic_num) == 1:
@@ -37,7 +37,7 @@ def view_raw_2(name = None, topic_num = None, num = None, doc_acl = 0, bbs_num =
             
             if comment_num != '':
                 sub += ' (' + comment_num + ')'
-        elif not topic_num and num:
+        elif topic_num == '' and num != '':
             curs.execute(db_change("select title from history where title = ? and id = ? and hide = 'O'"), [name, num])
             if curs.fetchall() and admin_check(6) != 1:
                 return re_error('/error/3')
@@ -47,7 +47,7 @@ def view_raw_2(name = None, topic_num = None, num = None, doc_acl = 0, bbs_num =
             sub += ' (r' + num + ')'
 
             menu = [['history_tool/' + url_pas(num) + '/' + url_pas(name), load_lang('return')]]
-        elif topic_num:
+        elif topic_num != '':
             if admin_check(6) != 1:
                 curs.execute(db_change("select data from topic where id = ? and code = ? and block = ''"), [num, topic_num])
             else:
@@ -84,7 +84,20 @@ def view_raw_2(name = None, topic_num = None, num = None, doc_acl = 0, bbs_num =
             data = curs.fetchall()
             
         if data:
-            p_data += '<textarea readonly class="opennamu_textarea_500">' + html.escape(data[0][0]) + '</textarea>'
+            doc_preview = ''
+            if bbs_num == '' and post_num == '' and topic_num == '':
+                doc_preview = '''
+                    <textarea id="opennamu_editor_doc_name" style="display: none;">''' + html.escape(name) + '''</textarea>
+                    <button id="opennamu_preview_button" type="button" onclick="opennamu_do_editor_preview('raw');">''' + load_lang('preview') + '''</button>
+                    <hr class="main_hr">
+                '''
+
+            p_data += '''
+                <div id="opennamu_preview_area">
+                    ''' + doc_preview + '''
+                    <textarea readonly id="opennamu_edit_textarea" class="opennamu_textarea_500">''' + html.escape(data[0][0]) + '''</textarea>
+                </div>
+            '''
             
             if doc_acl == 1:
                 p_data = '' + \

+ 5 - 4
route/view_acl.py → route/view_set.py

@@ -1,6 +1,6 @@
 from .tool.func import *
 
-def view_acl(name):
+def view_set(name = 'Test'):
     with get_db_connect() as conn:
         curs = conn.cursor()
 
@@ -34,7 +34,7 @@ def view_acl(name):
                     check_ok = 'disabled'
 
         if flask.request.method == 'POST':
-            acl_data = ['decu', 'document_edit_acl', 'document_move_acl', 'document_delete_acl', 'dis', 'view', 'why']
+            acl_data = ['decu', 'document_edit_acl', 'document_edit_request_acl', 'document_move_acl', 'document_delete_acl', 'dis', 'view', 'why']
 
             for i in acl_data:
                 form_data = flask.request.form.get(i, '')
@@ -93,6 +93,7 @@ def view_acl(name):
                     [load_lang('view_acl'), 'view', '3'],
                     [load_lang('document_acl'), 'decu', '4'],
                     [load_lang('document_edit_acl'), 'document_edit_acl', '5'],
+                    [load_lang('document_edit_request_acl'), 'document_edit_request_acl', '5'],
                     [load_lang('document_move_acl'), 'document_move_acl', '5'],
                     [load_lang('document_delete_acl'), 'document_delete_acl', '5'],
                     [load_lang('discussion_acl'), 'dis', '3'],
@@ -105,7 +106,6 @@ def view_acl(name):
             for i in acl_get_list:
                 data += '' + \
                     '<h' + i[2] + '>' + i[0] + '</h' + i[2] + '>' + \
-                    '<hr class="main_hr">' + \
                     '<select name="' + i[1] + '" ' + check_ok + '>' + \
                 ''
 
@@ -154,8 +154,9 @@ def view_acl(name):
                     <li>ban_admin : ''' + load_lang('ban_admin_acl') + '''</li>
                     <li>not_all : ''' + load_lang('not_all_acl') + '''</li>
                     <li>90_day : ''' + load_lang('90_day_acl') + '''</li>
+                    <li>up_to_level_3 : ''' + load_lang('up_to_level_3') + '''</li>
+                    <li>up_to_level_10 : ''' + load_lang('up_to_level_10') + '''</li>
                 </ul>
-                <hr class="main_hr">
                 <h2>''' + load_lang('markup') + '''</h2>
             '''
 

+ 17 - 16
route/view_read.py → route/view_w.py

@@ -1,6 +1,6 @@
 from .tool.func import *
 
-def view_read(name = 'Test', do_type = ''):
+def view_w(name = 'Test', do_type = ''):
     with get_db_connect() as conn:
         curs = conn.cursor()
 
@@ -83,10 +83,12 @@ def view_read(name = 'Test', do_type = ''):
         elif re.search(r"^user:([^/]*)", name):
             name_view = name
             doc_type = 'user'
+            user_name = ''
 
             match = re.search(r"^user:([^/]*)", name)
+            if match:
+                user_name = html.escape(match.group(1))
             
-            user_name = html.escape(match.group(1))
             user_doc = ''
             
             # S admin or owner 특수 틀 추가
@@ -160,16 +162,17 @@ def view_read(name = 'Test', do_type = ''):
         else:
             name_view = name
 
-        curs.execute(db_change("select data from data where title = ?"), [name])
+        end_data = '''
+            <div id="opennamu_preview_area">
+                <textarea id="opennamu_editor_doc_name" style="display: none;">''' + html.escape(name) + '''</textarea>
+                <script>opennamu_view_w();</script>
+            </div>
+        '''
 
+        curs.execute(db_change("select title from data where title = ?"), [name])
         data = curs.fetchall()
-        end_data = render_set(
-            doc_name = name,
-            doc_data = data[0][0] if data else None,
-            data_type = 'from' if do_type == 'from' else 'view'
-        )
 
-        if end_data == 'HTTP Request 401.3':
+        if acl_check(name, 'render') == 1:
             response_data = 401
 
             curs.execute(db_change('select data from other where name = "error_401"'))
@@ -178,7 +181,7 @@ def view_read(name = 'Test', do_type = ''):
                 end_data = '<h2>' + load_lang('error') + '</h2><ul class="opennamu_ul"><li>' + sql_d[0][0] + '</li></ul>'
             else:
                 end_data = '<h2>' + load_lang('error') + '</h2><ul class="opennamu_ul"><li>' + load_lang('authority_error') + '</li></ul>'
-        elif end_data == 'HTTP Request 404':
+        elif not data:
             response_data = 404
 
             curs.execute(db_change('select data from other where name = "error_404"'))
@@ -188,10 +191,7 @@ def view_read(name = 'Test', do_type = ''):
             else:
                 end_data = '<h2>' + load_lang('error') + '</h2><ul class="opennamu_ul"><li>' + load_lang('decument_404_error') + '</li></ul>'
 
-            curs.execute(db_change('' + \
-                'select ip, date, leng, send, id from history ' + \
-                'where title = ? and hide != "O" order by id + 0 desc limit 3' + \
-            ''), [name])
+            curs.execute(db_change('select ip, date, leng, send, id from history where title = ? and hide != "O" order by id + 0 desc limit 3'), [name])
             sql_d = curs.fetchall()
             if sql_d:
                 end_data += '<h2>' + load_lang('history') + '</h2><ul class="opennamu_ul">'
@@ -211,7 +211,7 @@ def view_read(name = 'Test', do_type = ''):
 
         curs.execute(db_change("select title from acl where title = ?"), [name])
         acl = 1 if curs.fetchall() else 0
-        menu_acl = 1 if acl_check(name) == 1 else 0
+        menu_acl = 1 if acl_check(name, 'document_edit') == 1 else 0
         if response_data == 404:
             menu += [['edit/' + url_pas(name), load_lang('create'), menu_acl]] 
         else:
@@ -317,8 +317,9 @@ def view_read(name = 'Test', do_type = ''):
         div += body[0][0] if body else ''
 
         if ip_or_user(ip) == 0:
-            curs.execute(db_change("select title from scan where user = ? and title = ?"), [ip, name])
+            curs.execute(db_change("select data from user_set where id = ? and data = ?"), [ip, name])
             watch_list = 2 if curs.fetchall() else 1
+            menu += [['star_doc_from/' + url_pas(name), ('☆' if watch_list == 1 else '★'), watch_list - 1]]
         else:
             watch_list = 0
 

+ 40 - 0
route/view_w_raw.py

@@ -0,0 +1,40 @@
+from .tool.func import *
+
+def view_w_raw(name = '', rev = '', doc_acl = ''):
+    with get_db_connect() as conn:
+        rev_str = str(rev)
+
+        sub = '(' + load_lang('raw') + ')'
+        sub += ' (' + rev_str + ')' if rev != '' else ''
+
+        if rev != '':
+            menu = [['history_tool/' + rev_str + '/' + url_pas(name), load_lang('return')]]
+        else:
+            menu = [['w/' + url_pas(name), load_lang('return')]]
+
+        p_data = ''
+        p_data += '''
+            <div id="opennamu_preview_area">
+                <textarea id="opennamu_editor_doc_name" style="display: none;">''' + html.escape(name) + '''</textarea>
+                <textarea id="opennamu_editor_rev" style="display: none;">''' + rev_str + '''</textarea>
+                <button id="opennamu_preview_button" type="button" onclick="opennamu_view_w_raw_preview();">''' + load_lang('preview') + '''</button>
+                <hr class="main_hr">
+                <textarea readonly id="opennamu_edit_textarea" class="opennamu_textarea_500"></textarea>
+                <script>opennamu_view_w_raw();</script>
+            </div>
+        '''
+        
+        if doc_acl == 'on':
+            p_data = '' + \
+                load_lang('authority_error') + \
+                '<hr class="main_hr">' + \
+                p_data
+            ''
+            
+            sub = ' (' + load_lang('edit') + ')'
+
+        return easy_minify(flask.render_template(skin_check(),
+            imp = [name, wiki_set(), wiki_custom(), wiki_css([sub, 0])],
+            data = p_data,
+            menu = menu
+        ))

+ 0 - 21
route_go/api_func_sha224.go

@@ -1,21 +0,0 @@
-package main
-
-import (
-	"crypto/sha256"
-	"encoding/hex"
-	"fmt"
-	"os"
-)
-
-func main() {
-	call_arg := os.Args[1:]
-
-	data := call_arg[0]
-
-	hasher := sha256.New224()
-	hasher.Write([]byte(data))
-	hash_byte := hasher.Sum(nil)
-	hash_str := hex.EncodeToString(hash_byte)
-
-	fmt.Print(hash_str)
-}

BIN
route_go/bin/api_func_sha224.amd64.bin


BIN
route_go/bin/api_func_sha224.amd64.exe


BIN
route_go/bin/api_func_sha224.arm64.bin


BIN
route_go/bin/api_func_sha224.arm64.exe


BIN
route_go/bin/view_random.amd64.exe → route_go/bin/main.amd64.bin


BIN
route_go/bin/view_random.arm64.exe → route_go/bin/main.amd64.exe


BIN
route_go/bin/view_random.arm64.bin → route_go/bin/main.arm64.bin


BIN
route_go/bin/view_random.amd64.bin → route_go/bin/main.arm64.exe


BIN
route_go/bin/main_func_easter_egg.amd64.bin


BIN
route_go/bin/main_func_easter_egg.amd64.exe


BIN
route_go/bin/main_func_easter_egg.arm64.bin


BIN
route_go/bin/main_func_easter_egg.arm64.exe


+ 4 - 0
route_go/linux_amd64.sh

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

+ 34 - 0
route_go/main.go

@@ -0,0 +1,34 @@
+package main
+
+import (
+	"opennamu/route"
+	"os"
+)
+
+func main() {
+	call_arg := os.Args[1:]
+
+	if call_arg[0] == "main_func_easter_egg" {
+		route.Main_func_easter_egg()
+	} else if call_arg[0] == "api_w_raw" {
+		route.Api_w_raw(call_arg[1:])
+	} else if call_arg[0] == "api_func_sha224" {
+		route.Api_func_sha224(call_arg[1:])
+	} else if call_arg[0] == "api_w_random" {
+		route.Api_w_random(call_arg[1:])
+	} else if call_arg[0] == "api_search" {
+		route.Api_search(call_arg[1:])
+	} else if call_arg[0] == "api_topic" {
+		route.Api_thread(call_arg[1:])
+	} else if call_arg[0] == "api_func_ip" {
+		route.Api_func_ip(call_arg[1:])
+	} else if call_arg[0] == "api_recent_change" {
+		route.Api_recent_change(call_arg[1:])
+	} else if call_arg[0] == "api_recent_edit_request" {
+		route.Api_recent_edit_request(call_arg[1:])
+	} else if call_arg[0] == "api_bbs" {
+		route.Api_bbs(call_arg[1:])
+	} else if call_arg[0] == "api_w_xref" {
+		route.Api_w_xref(call_arg[1:])
+	}
+}

+ 101 - 0
route_go/route/api_bbs.go

@@ -0,0 +1,101 @@
+package route
+
+import (
+	"database/sql"
+	"encoding/json"
+	"fmt"
+	"opennamu/route/tool"
+	"strconv"
+)
+
+func Api_bbs(call_arg []string) {
+	db_set := map[string]string{}
+	json.Unmarshal([]byte(call_arg[0]), &db_set)
+
+	other_set := map[string]string{}
+	json.Unmarshal([]byte(call_arg[1]), &other_set)
+
+	db := tool.DB_connect(db_set)
+	if db == nil {
+		return
+	}
+	defer db.Close()
+
+	var rows *sql.Rows
+	if other_set["bbs_num"] == "" {
+		var err error
+
+		rows, err = db.Query(tool.DB_change(db_set, "select set_code, set_id from bbs_data where set_name = 'date' order by set_data desc limit 50"))
+		if err != nil {
+			return
+		}
+	} else {
+		page, _ := strconv.Atoi(other_set["page"])
+		num := 0
+		if page*50 > 0 {
+			num = page*50 - 50
+		}
+
+		stmt, err := db.Prepare(tool.DB_change(db_set, "select set_code, set_id from bbs_data where set_name = 'title' and set_id like ? order by set_code + 0 desc limit ?, 50"))
+		if err != nil {
+			return
+		}
+		defer stmt.Close()
+
+		rows, err = stmt.Query(other_set["bbs_num"], num)
+		if err != nil {
+			return
+		}
+	}
+	defer rows.Close()
+
+	var data_list []map[string]string
+
+	for rows.Next() {
+		temp_data := make(map[string]string)
+
+		var set_code string
+		var set_id string
+
+		err := rows.Scan(&set_code, &set_id)
+		if err != nil {
+			return
+		}
+
+		temp_data["set_code"] = set_code
+		temp_data["set_id"] = set_id
+
+		stmt, err := db.Prepare(tool.DB_change(db_set, "select set_name, set_data, set_code, set_id from bbs_data where set_code = ? and set_id = ?"))
+		if err != nil {
+			return
+		}
+		defer stmt.Close()
+
+		rows, err := stmt.Query(set_code, set_id)
+		if err != nil {
+			return
+		}
+		defer rows.Close()
+
+		for rows.Next() {
+			var set_name string
+			var set_data string
+
+			err := rows.Scan(&set_name, &set_data, &set_code, &set_id)
+			if err != nil {
+				return
+			}
+
+			temp_data[set_name] = set_data
+		}
+
+		data_list = append(data_list, temp_data)
+	}
+
+	if len(data_list) == 0 {
+		fmt.Print("{}")
+	} else {
+		json_data, _ := json.Marshal(data_list)
+		fmt.Print(string(json_data))
+	}
+}

+ 30 - 0
route_go/route/api_func_ip.go

@@ -0,0 +1,30 @@
+package route
+
+import (
+	"encoding/json"
+	"fmt"
+
+	"opennamu/route/tool"
+)
+
+func Api_func_ip(call_arg []string) {
+	db_set := map[string]string{}
+	json.Unmarshal([]byte(call_arg[0]), &db_set)
+
+	other_set := map[string]string{}
+	json.Unmarshal([]byte(call_arg[1]), &other_set)
+
+	db := tool.DB_connect(db_set)
+	if db == nil {
+		return
+	}
+	defer db.Close()
+
+	ip_data := tool.IP_parser(db, db_set, other_set["data"], other_set["ip"])
+
+	new_data := map[string]string{}
+	new_data["data"] = ip_data
+
+	json_data, _ := json.Marshal(new_data)
+	fmt.Print(string(json_data))
+}

+ 20 - 0
route_go/route/api_func_sha224.go

@@ -0,0 +1,20 @@
+package route
+
+import (
+	"encoding/json"
+	"fmt"
+
+	"opennamu/route/tool"
+)
+
+func Api_func_sha224(call_arg []string) {
+	data := call_arg[0]
+
+	hash_str := tool.Sha224(data)
+
+	new_data := map[string]string{}
+	new_data["data"] = hash_str
+
+	json_data, _ := json.Marshal(new_data)
+	fmt.Print(string(json_data))
+}

+ 112 - 0
route_go/route/api_recent_change.go

@@ -0,0 +1,112 @@
+package route
+
+import (
+	"database/sql"
+	"encoding/json"
+	"fmt"
+	"opennamu/route/tool"
+	"strconv"
+)
+
+func Api_recent_change(call_arg []string) {
+	db_set := map[string]string{}
+	json.Unmarshal([]byte(call_arg[0]), &db_set)
+
+	other_set := map[string]string{}
+	json.Unmarshal([]byte(call_arg[1]), &other_set)
+
+	db := tool.DB_connect(db_set)
+	if db == nil {
+		return
+	}
+	defer db.Close()
+
+	set_type := other_set["set_type"]
+	if set_type == "edit" {
+		set_type = ""
+	}
+
+	limit_int, err := strconv.Atoi(other_set["limit"])
+	if err != nil {
+		return
+	}
+
+	if limit_int > 50 || limit_int < 0 {
+		limit_int = 50
+	}
+
+	stmt, err := db.Prepare(tool.DB_change(db_set, "select id, title from rc where type = ? order by date desc limit ?"))
+	if err != nil {
+		return
+	}
+	defer stmt.Close()
+
+	rows, err := stmt.Query(set_type, limit_int)
+	if err != nil {
+		return
+	}
+	defer rows.Close()
+
+	var id string
+	var title string
+
+	var data_list [][]string
+	admin_auth := tool.Get_admin_auth(db, db_set, other_set["ip"])
+
+	for rows.Next() {
+		err := rows.Scan(&id, &title)
+		if err != nil {
+			return
+		}
+
+		var date string
+		var ip string
+		var send string
+		var leng string
+		var hide string
+		var type_data string
+
+		stmt, err := db.Prepare(tool.DB_change(db_set, "select date, ip, send, leng, hide, type from history where id = ? and title = ?"))
+		if err != nil {
+			return
+		}
+		defer stmt.Close()
+
+		err = stmt.QueryRow(id, title).Scan(&date, &ip, &send, &leng, &hide, &type_data)
+		if err != nil {
+			if err == sql.ErrNoRows {
+				date = ""
+				ip = ""
+				send = ""
+				leng = ""
+				hide = ""
+				type_data = ""
+			} else {
+				return
+			}
+		}
+
+		if hide == "" || admin_auth != "" {
+			data_list = append(data_list, []string{
+				id,
+				title,
+				date,
+				tool.IP_preprocess(db, db_set, ip, other_set["ip"])[0],
+				send,
+				leng,
+				hide,
+				tool.IP_parser(db, db_set, ip, other_set["ip"]),
+				type_data,
+			})
+		} else {
+			data_list = append(data_list, []string{"", "", "", "", "", "", hide, "", ""})
+		}
+	}
+
+	if len(data_list) == 0 {
+		fmt.Print("{}")
+	} else {
+		json_data, _ := json.Marshal(data_list)
+		fmt.Print(string(json_data))
+	}
+}

+ 122 - 0
route_go/route/api_recent_edit_request.go

@@ -0,0 +1,122 @@
+package route
+
+import (
+	"database/sql"
+	"encoding/json"
+	"fmt"
+	"opennamu/route/tool"
+	"strconv"
+)
+
+func Api_recent_edit_request(call_arg []string) {
+	db_set := map[string]string{}
+	json.Unmarshal([]byte(call_arg[0]), &db_set)
+
+	other_set := map[string]string{}
+	json.Unmarshal([]byte(call_arg[1]), &other_set)
+
+	db := tool.DB_connect(db_set)
+	if db == nil {
+		return
+	}
+	defer db.Close()
+
+	limit_int, err := strconv.Atoi(other_set["limit"])
+	if err != nil {
+		return
+	}
+
+	if limit_int > 50 || limit_int < 0 {
+		limit_int = 50
+	}
+
+	stmt, err := db.Prepare(tool.DB_change(db_set, "select doc_name, doc_rev, set_data from data_set where set_name = 'edit_request_doing' order by set_data desc limit ?"))
+	if err != nil {
+		return
+	}
+	defer stmt.Close()
+
+	rows, err := stmt.Query(limit_int)
+	if err != nil {
+		return
+	}
+	defer rows.Close()
+
+	var doc_name string
+	var doc_rev string
+	var date string
+
+	var data_list [][]string
+	for rows.Next() {
+		err := rows.Scan(&doc_name, &doc_rev, &date)
+		if err != nil {
+			return
+		}
+
+		var ip string
+		var send string
+		var leng string
+
+		stmt, err := db.Prepare(tool.DB_change(db_set, "select set_data from data_set where set_name = 'edit_request_user' and doc_rev = ? and doc_name = ?"))
+		if err != nil {
+			return
+		}
+		defer stmt.Close()
+
+		err = stmt.QueryRow(doc_rev, doc_name).Scan(&ip)
+		if err != nil {
+			if err == sql.ErrNoRows {
+				ip = ""
+			} else {
+				return
+			}
+		}
+
+		stmt, err = db.Prepare(tool.DB_change(db_set, "select set_data from data_set where set_name = 'edit_request_send' and doc_rev = ? and doc_name = ?"))
+		if err != nil {
+			return
+		}
+		defer stmt.Close()
+
+		err = stmt.QueryRow(doc_rev, doc_name).Scan(&send)
+		if err != nil {
+			if err == sql.ErrNoRows {
+				send = ""
+			} else {
+				return
+			}
+		}
+
+		stmt, err = db.Prepare(tool.DB_change(db_set, "select set_data from data_set where set_name = 'edit_request_leng' and doc_rev = ? and doc_name = ?"))
+		if err != nil {
+			return
+		}
+		defer stmt.Close()
+
+		err = stmt.QueryRow(doc_rev, doc_name).Scan(&leng)
+		if err != nil {
+			if err == sql.ErrNoRows {
+				leng = ""
+			} else {
+				return
+			}
+		}
+
+		data_list = append(data_list, []string{
+			doc_name,
+			doc_rev,
+			date,
+			tool.IP_preprocess(db, db_set, ip, other_set["ip"])[0],
+			send,
+			leng,
+			tool.IP_parser(db, db_set, ip, other_set["ip"]),
+		})
+	}
+
+	if len(data_list) == 0 {
+		fmt.Print("{}")
+	} else {
+		json_data, _ := json.Marshal(data_list)
+		fmt.Print(string(json_data))
+	}
+}

+ 93 - 0
route_go/route/api_search.go

@@ -0,0 +1,93 @@
+package route
+
+import (
+	"encoding/json"
+	"fmt"
+	"strconv"
+
+	"opennamu/route/tool"
+)
+
+func Api_search(call_arg []string) {
+	db_set := map[string]string{}
+	json.Unmarshal([]byte(call_arg[0]), &db_set)
+
+	other_set := map[string]string{}
+	json.Unmarshal([]byte(call_arg[1]), &other_set)
+
+	page, _ := strconv.Atoi(other_set["num"])
+	num := 0
+	if page*50 > 0 {
+		num = page*50 - 50
+	}
+
+	db := tool.DB_connect(db_set)
+	if db == nil {
+		return
+	}
+	defer db.Close()
+
+	if other_set["search_type"] == "title" {
+		stmt, err := db.Prepare(tool.DB_change(db_set, "select title from data where title collate nocase like ? order by title limit ?, 50"))
+		if err != nil {
+			return
+		}
+		defer stmt.Close()
+
+		var title string
+		var title_list []string
+
+		rows, err := stmt.Query("%"+other_set["name"]+"%", num)
+		if err != nil {
+			return
+		}
+		defer rows.Close()
+
+		for rows.Next() {
+			err := rows.Scan(&title)
+			if err != nil {
+				return
+			}
+
+			title_list = append(title_list, title)
+		}
+
+		if len(title_list) == 0 {
+			fmt.Print("{}")
+		} else {
+			json_data, _ := json.Marshal(title_list)
+			fmt.Print(string(json_data))
+		}
+	} else {
+		stmt, err := db.Prepare(tool.DB_change(db_set, "select title from data where data collate nocase like ? order by title limit ?, 50"))
+		if err != nil {
+			return
+		}
+		defer stmt.Close()
+
+		var title string
+		var title_list []string
+
+		rows, err := stmt.Query("%"+other_set["name"]+"%", num)
+		if err != nil {
+			return
+		}
+		defer rows.Close()
+
+		for rows.Next() {
+			err := rows.Scan(&title)
+			if err != nil {
+				return
+			}
+
+			title_list = append(title_list, title)
+		}
+
+		if len(title_list) == 0 {
+			fmt.Print("{}")
+		} else {
+			json_data, _ := json.Marshal(title_list)
+			fmt.Print(string(json_data))
+		}
+	}
+}

+ 130 - 0
route_go/route/api_thread.go

@@ -0,0 +1,130 @@
+package route
+
+import (
+	"database/sql"
+	"encoding/json"
+	"fmt"
+
+	"opennamu/route/tool"
+)
+
+func Api_thread(call_arg []string) {
+	db_set := map[string]string{}
+	json.Unmarshal([]byte(call_arg[0]), &db_set)
+
+	other_set := map[string]string{}
+	json.Unmarshal([]byte(call_arg[1]), &other_set)
+
+	db := tool.DB_connect(db_set)
+	if db == nil {
+		return
+	}
+	defer db.Close()
+
+	if other_set["tool"] == "length" {
+		stmt, err := db.Prepare(tool.DB_change(db_set, "select id from topic where code = ? order by id + 0 desc limit 1"))
+		if err != nil {
+			return
+		}
+		defer stmt.Close()
+
+		var length string
+		err = stmt.QueryRow(other_set["topic_num"]).Scan(&length)
+		if err != nil {
+			if err == sql.ErrNoRows {
+				length = "0"
+			} else {
+				return
+			}
+		}
+
+		new_data := map[string]string{}
+		new_data["length"] = length
+
+		json_data, _ := json.Marshal(new_data)
+		fmt.Print(string(json_data))
+	} else {
+		var rows *sql.Rows
+
+		if other_set["tool"] == "top" {
+			stmt, err := db.Prepare(tool.DB_change(db_set, "select id, data, date, ip, block, top from topic where code = ? and top = 'O' order by id + 0 asc"))
+			if err != nil {
+				return
+			}
+			defer stmt.Close()
+
+			rows, err = stmt.Query(other_set["topic_num"])
+			if err != nil {
+				return
+			}
+		} else {
+			if other_set["s_num"] != "" && other_set["e_num"] != "" {
+				stmt, err := db.Prepare(tool.DB_change(db_set, "select id, data, date, ip, block, top from topic where code = ? and ? + 0 <= id + 0 and id + 0 <= ? + 0 order by id + 0 asc"))
+				if err != nil {
+					return
+				}
+				defer stmt.Close()
+
+				rows, err = stmt.Query(other_set["topic_num"], other_set["s_num"], other_set["e_num"])
+				if err != nil {
+					return
+				}
+			} else {
+				stmt, err := db.Prepare(tool.DB_change(db_set, "select id, data, date, ip, block, top from topic where code = ? order by id + 0 asc"))
+				if err != nil {
+					return
+				}
+				defer stmt.Close()
+
+				rows, err = stmt.Query(other_set["topic_num"])
+				if err != nil {
+					return
+				}
+			}
+		}
+		defer rows.Close()
+
+		var id, data, date, ip, block, top string
+		var data_list [][]string
+
+		for rows.Next() {
+			err := rows.Scan(&id, &data, &date, &ip, &block, &top)
+			if err != nil {
+				return
+			}
+
+			data_list = append(data_list, []string{id, data, date, ip, block, top})
+		}
+
+		new_data := make(map[string]interface{})
+		new_data["data"] = []map[string]string{}
+		data_slice := []map[string]string{}
+
+		admin_auth := tool.Get_admin_auth(db, db_set, other_set["ip"])
+
+		for for_a := 0; for_a < len(data_list); for_a++ {
+			data := ""
+			if data_list[for_a][4] != "O" || admin_auth != "" {
+				data = data_list[for_a][1]
+			}
+
+			data_slice = append(data_slice, map[string]string{
+				"id":        data_list[for_a][0],
+				"data":      data,
+				"date":      data_list[for_a][2],
+				"ip":        tool.IP_preprocess(db, db_set, data_list[for_a][3], other_set["ip"])[0],
+				"ip_render": tool.IP_parser(db, db_set, data_list[for_a][3], other_set["ip"]),
+				"blind":     data_list[for_a][4],
+			})
+		}
+
+		new_data["data"] = data_slice
+		new_data["language"] = map[string]string{
+			"tool":   tool.Get_language(db, db_set, "tool", false),
+			"render": tool.Get_language(db, db_set, "render", false),
+		}
+
+		json_data, _ := json.Marshal(new_data)
+		fmt.Print(string(json_data))
+	}
+}

+ 15 - 9
route_go/view_random.go → route_go/route/api_w_random.go

@@ -1,16 +1,14 @@
-package main
+package route
 
 import (
+	"database/sql"
 	"encoding/json"
 	"fmt"
-	"os"
 
-	"opennamu/tool"
+	"opennamu/route/tool"
 )
 
-func main() {
-	call_arg := os.Args[1:]
-
+func Api_w_random(call_arg []string) {
 	db_set := map[string]string{}
 	json.Unmarshal([]byte(call_arg[0]), &db_set)
 
@@ -21,11 +19,19 @@ func main() {
 	defer db.Close()
 
 	var title string
+
 	err := db.QueryRow(tool.DB_change(db_set, "select title from data where title not like 'user:%' and title not like 'category:%' and title not like 'file:%' order by random() limit 1")).Scan(&title)
 	if err != nil {
-		fmt.Println(err)
-		return
+		if err == sql.ErrNoRows {
+			title = ""
+		} else {
+			return
+		}
 	}
 
-	fmt.Print(title)
+	new_data := map[string]string{}
+	new_data["data"] = title
+
+	json_data, _ := json.Marshal(new_data)
+	fmt.Print(string(json_data))
 }

+ 92 - 0
route_go/route/api_w_raw.go

@@ -0,0 +1,92 @@
+package route
+
+import (
+	"database/sql"
+	"encoding/json"
+	"fmt"
+
+	"opennamu/route/tool"
+)
+
+func Api_w_raw(call_arg []string) {
+	db_set := map[string]string{}
+	json.Unmarshal([]byte(call_arg[0]), &db_set)
+
+	other_set := map[string]string{}
+	json.Unmarshal([]byte(call_arg[1]), &other_set)
+
+	db := tool.DB_connect(db_set)
+	if db == nil {
+		return
+	}
+	defer db.Close()
+
+	if other_set["exist_check"] != "" {
+		stmt, err := db.Prepare(tool.DB_change(db_set, "select title from data where title = ?"))
+		if err != nil {
+			return
+		}
+		defer stmt.Close()
+
+		new_data := map[string]string{}
+		var title string
+
+		err = stmt.QueryRow(other_set["name"]).Scan(&title)
+		if err != nil {
+			if err == sql.ErrNoRows {
+			} else {
+				return
+			}
+		} else {
+			new_data["exist"] = "1"
+		}
+
+		json_data, _ := json.Marshal(new_data)
+		fmt.Print(string(json_data))
+	} else {
+		new_data := map[string]string{}
+		var data string
+
+		if other_set["rev"] != "" {
+			stmt, err := db.Prepare(tool.DB_change(db_set, "select data from history where title = ? and id = ?"))
+			if err != nil {
+				return
+			}
+			defer stmt.Close()
+
+			err = stmt.QueryRow(other_set["name"], other_set["rev"]).Scan(&data)
+			if err != nil {
+				if err == sql.ErrNoRows {
+				} else {
+					return
+				}
+			} else {
+				new_data["title"] = other_set["name"]
+				new_data["data"] = data
+			}
+
+			json_data, _ := json.Marshal(new_data)
+			fmt.Print(string(json_data))
+		} else {
+			stmt, err := db.Prepare(tool.DB_change(db_set, "select data from data where title = ?"))
+			if err != nil {
+				return
+			}
+			defer stmt.Close()
+
+			err = stmt.QueryRow(other_set["name"]).Scan(&data)
+			if err != nil {
+				if err == sql.ErrNoRows {
+				} else {
+					return
+				}
+			} else {
+				new_data["title"] = other_set["name"]
+				new_data["data"] = data
+			}
+
+			json_data, _ := json.Marshal(new_data)
+			fmt.Print(string(json_data))
+		}
+	}
+}

+ 83 - 0
route_go/route/api_w_xref.go

@@ -0,0 +1,83 @@
+package route
+
+import (
+	"database/sql"
+	"encoding/json"
+	"fmt"
+	"opennamu/route/tool"
+	"strconv"
+)
+
+func Api_w_xref(call_arg []string) {
+	db_set := map[string]string{}
+	json.Unmarshal([]byte(call_arg[0]), &db_set)
+
+	other_set := map[string]string{}
+	json.Unmarshal([]byte(call_arg[1]), &other_set)
+
+	db := tool.DB_connect(db_set)
+	if db == nil {
+		return
+	}
+	defer db.Close()
+
+	page, _ := strconv.Atoi(other_set["page"])
+	num := 0
+	if page*50 > 0 {
+		num = page*50 - 50
+	}
+
+	var link_case_insensitive string
+
+	err := db.QueryRow(tool.DB_change(db_set, "select data from other where name = 'link_case_insensitive'")).Scan(&link_case_insensitive)
+	if err != nil {
+		if err == sql.ErrNoRows {
+			link_case_insensitive = ""
+		} else {
+			return
+		}
+	}
+
+	if link_case_insensitive != "" {
+		link_case_insensitive = " collate nocase"
+	}
+
+	var stmt *sql.Stmt
+	if other_set["do_type"] == "1" {
+		stmt, err = db.Prepare(tool.DB_change(db_set, "select distinct link, type from back where title"+link_case_insensitive+" = ? and not type = 'no' and not type = 'nothing' order by type asc, link asc limit ?, 50"))
+	} else {
+		stmt, err = db.Prepare(tool.DB_change(db_set, "select distinct title, type from back where link"+link_case_insensitive+" = ? and not type = 'no' and not type = 'nothing' order by type asc, title asc limit ?, 50"))
+	}
+
+	if err != nil {
+		return
+	}
+	defer stmt.Close()
+
+	rows, err := stmt.Query(other_set["name"], num)
+	if err != nil {
+		return
+	}
+	defer rows.Close()
+
+	var name string
+	var type_data string
+
+	var data_list [][]string
+
+	for rows.Next() {
+		err := rows.Scan(&name, &type_data)
+		if err != nil {
+			return
+		}
+
+		data_list = append(data_list, []string{name, type_data})
+	}
+
+	if len(data_list) == 0 {
+		fmt.Print("{}")
+	} else {
+		json_data, _ := json.Marshal(data_list)
+		fmt.Print(string(json_data))
+	}
+}

+ 2 - 2
route_go/main_func_easter_egg.go → route_go/route/main_func_easter_egg.go

@@ -1,11 +1,11 @@
-package main
+package route
 
 import (
 	"fmt"
 	"math/rand"
 )
 
-func main() {
+func Main_func_easter_egg() {
 	select_list := []string{
 		"PWD0ZbR7AOY", // Shanghai Teahouse ~ Chinese Tea
 		"HoU29ljOmTE", // Flawless Clothing of Celestials

+ 0 - 0
route_go/tool/db_connect.go → route_go/route/tool/db_connect.go


+ 226 - 0
route_go/route/tool/ip_parser.go

@@ -0,0 +1,226 @@
+package tool
+
+import (
+	"database/sql"
+	"regexp"
+	"strconv"
+)
+
+func IP_or_user(ip string) bool {
+	match, _ := regexp.MatchString("(\\.|:)", ip)
+	if match {
+		return true
+	} else {
+		return false
+	}
+}
+
+func Get_level(db *sql.DB, db_set map[string]string, ip string) []string {
+	var level string
+	var exp string
+	var max_exp string
+
+	stmt, err := db.Prepare(DB_change(db_set, "select data from user_set where id = ? and name = 'level'"))
+	if err != nil {
+		return []string{"", "", ""}
+	}
+	defer stmt.Close()
+
+	err = stmt.QueryRow(ip).Scan(&level)
+	if err != nil {
+		if err == sql.ErrNoRows {
+			level = "0"
+		} else {
+			return []string{"", "", ""}
+		}
+	}
+
+	stmt, err = db.Prepare(DB_change(db_set, "select data from user_set where id = ? and name = 'experience'"))
+	if err != nil {
+		return []string{"", "", ""}
+	}
+	defer stmt.Close()
+
+	err = stmt.QueryRow(ip).Scan(&exp)
+	if err != nil {
+		if err == sql.ErrNoRows {
+			exp = "0"
+		} else {
+			return []string{"", "", ""}
+		}
+	}
+
+	level_int, _ := strconv.Atoi(level)
+	max_exp = strconv.Itoa(level_int*50 + 500)
+
+	return []string{level, exp, max_exp}
+}
+
+func Get_admin_auth(db *sql.DB, db_set map[string]string, ip string) string {
+	if !IP_or_user(ip) {
+		var auth string
+
+		stmt, err := db.Prepare(DB_change(db_set, "select data from user_set where id = ? and name = 'acl'"))
+		if err != nil {
+			return ""
+		}
+		defer stmt.Close()
+
+		err = stmt.QueryRow(ip).Scan(&auth)
+		if err != nil {
+			if err == sql.ErrNoRows {
+				auth = "user"
+			} else {
+				return ""
+			}
+		}
+
+		if auth != "user" {
+			return auth
+		} else {
+			return ""
+		}
+	}
+
+	return ""
+}
+
+func IP_preprocess(db *sql.DB, db_set map[string]string, ip string, my_ip string) []string {
+	var ip_view string
+	var user_name_view string
+
+	err := db.QueryRow(DB_change(db_set, "select data from other where name = 'ip_view'")).Scan(&ip_view)
+	if err != nil {
+		if err == sql.ErrNoRows {
+			ip_view = ""
+		} else {
+			return []string{"", ""}
+		}
+	}
+
+	err = db.QueryRow(DB_change(db_set, "select data from other where name = 'user_name_view'")).Scan(&user_name_view)
+	if err != nil {
+		if err == sql.ErrNoRows {
+			user_name_view = ""
+		} else {
+			return []string{"", ""}
+		}
+	}
+
+	if Get_admin_auth(db, db_set, my_ip) != "" {
+		ip_view = ""
+		user_name_view = ""
+	}
+
+	ip_change := ""
+	if IP_or_user(ip) {
+		if ip_view != "" && ip != my_ip {
+			hash_ip := Sha224(ip)
+			ip = hash_ip[:10]
+			ip_change = "true"
+		}
+	} else {
+		if user_name_view != "" {
+			var sub_user_name string
+
+			stmt, err := db.Prepare(DB_change(db_set, "select data from user_set where id = ? and name = 'sub_user_name'"))
+			if err != nil {
+				return []string{"", ""}
+			}
+			defer stmt.Close()
+
+			err = stmt.QueryRow(ip).Scan(&sub_user_name)
+			if err != nil {
+				if err == sql.ErrNoRows {
+					sub_user_name = "user"
+				} else {
+					return []string{"", ""}
+				}
+			}
+
+			ip = sub_user_name
+			ip_change = "true"
+		} else {
+			var user_name string
+
+			stmt, err := db.Prepare(DB_change(db_set, "select data from user_set where name = 'user_name' and id = ?"))
+			if err != nil {
+				return []string{"", ""}
+			}
+			defer stmt.Close()
+
+			err = stmt.QueryRow(ip).Scan(&user_name)
+			if err != nil {
+				if err == sql.ErrNoRows {
+					user_name = ip
+				} else {
+					return []string{"", ""}
+				}
+			}
+
+			ip = user_name
+		}
+	}
+
+	return []string{ip, ip_change}
+}
+
+func IP_parser(db *sql.DB, db_set map[string]string, ip string, my_ip string) string {
+	ip_pre_data := IP_preprocess(db, db_set, ip, my_ip)
+	if ip_pre_data[0] == "" {
+		return ""
+	}
+
+	if ip_pre_data[1] != "" {
+		return ip_pre_data[0]
+	} else {
+		raw_ip := ip
+		ip = HTML_escape(ip_pre_data[0])
+
+		if !IP_or_user(raw_ip) {
+			var user_name_level string
+			var user_title string
+
+			err := db.QueryRow(DB_change(db_set, "select data from other where name = 'user_name_view'")).Scan(&user_name_level)
+			if err != nil {
+				if err == sql.ErrNoRows {
+					user_name_level = ""
+				} else {
+					return ""
+				}
+			}
+
+			if user_name_level != "" {
+				level_data := Get_level(db, db_set, raw_ip)
+				ip += "<sup>" + level_data[0] + "</sup>"
+			}
+
+			ip = "<a href=\"/w/" + Url_parser("user:"+raw_ip) + "\">" + ip + "</a>"
+
+			stmt, err := db.Prepare(DB_change(db_set, "select data from user_set where name = 'user_title' and id = ?"))
+			if err != nil {
+				return ""
+			}
+			defer stmt.Close()
+
+			err = stmt.QueryRow(raw_ip).Scan(&user_title)
+			if err != nil {
+				if err == sql.ErrNoRows {
+					user_title = ""
+				} else {
+					return ""
+				}
+			}
+
+			if Get_admin_auth(db, db_set, ip) != "" {
+				ip = "<b>" + ip + "</b>"
+			}
+
+			ip = user_title + ip
+		}
+
+		ip += " <a href=\"/user/" + Url_parser(raw_ip) + "\">(" + Get_language(db, db_set, "tool", false) + ")</a>"
+
+		return ip
+	}
+}

+ 41 - 0
route_go/route/tool/language.go

@@ -0,0 +1,41 @@
+package tool
+
+import (
+	"database/sql"
+	"encoding/json"
+	"fmt"
+	"os"
+)
+
+func Get_language(db *sql.DB, db_set map[string]string, data string, safe bool) string {
+	var language string
+
+	err := db.QueryRow(DB_change(db_set, "select data from other where name = 'language'")).Scan(&language)
+	if err != nil {
+		if err == sql.ErrNoRows {
+			language = "ko-KR"
+		} else {
+			return ""
+		}
+	}
+
+	file, err := os.Open("./lang/" + language + ".json")
+	if err != nil {
+		fmt.Print(err)
+		return ""
+	}
+	defer file.Close()
+
+	lang_data := map[string]string{}
+
+	decoder := json.NewDecoder(file)
+	if err := decoder.Decode(&lang_data); err != nil {
+		return ""
+	}
+
+	if safe {
+		return lang_data[data]
+	} else {
+		return HTML_escape(lang_data[data])
+	}
+}

+ 10 - 0
route_go/route/tool/namumark.go

@@ -0,0 +1,10 @@
+package tool
+
+func Namumark() map[string]interface{} {
+	end_data := make(map[string]interface{})
+	end_data["data"] = ""
+	end_data["js_data"] = ""
+	end_data["backlink"] = []string{}
+
+	return end_data
+}

+ 61 - 0
route_go/route/tool/render.go

@@ -0,0 +1,61 @@
+package tool
+
+import (
+	"database/sql"
+	"strconv"
+	"time"
+)
+
+func Get_render(db *sql.DB, db_set map[string]string, doc_name string, data string, render_type string) []string {
+	var markup string
+
+	if render_type == "document" {
+		stmt, err := db.Prepare(DB_change(db_set, "select set_data from data_set where doc_name = ? and set_name = 'document_markup'"))
+		if err != nil {
+			return []string{"", ""}
+		}
+		defer stmt.Close()
+
+		err = stmt.QueryRow(doc_name).Scan(&markup)
+		if err != nil {
+			if err == sql.ErrNoRows {
+				markup = ""
+			} else {
+				return []string{"", ""}
+			}
+		}
+	}
+
+	err := db.QueryRow(DB_change(db_set, "select data from other where name = 'markup'")).Scan(&markup)
+	if err != nil {
+		if err == sql.ErrNoRows {
+			markup = ""
+		} else {
+			return []string{"", ""}
+		}
+	}
+
+	if markup == "" {
+		markup = "namumark"
+	}
+
+	now_time := time.Now().UnixNano()
+	render_name := strconv.Itoa(int(now_time))
+
+	render_data := Get_render_direct(db, db_set, doc_name, data, markup, render_name, render_type)
+
+	return render_data
+}
+
+func Get_render_direct(db *sql.DB, db_set map[string]string, doc_name string, data string, markup string, render_name string, render_type string) []string {
+	render_data := make(map[string]interface{})
+	if markup == "namumark" {
+		render_data = Namumark()
+	} else {
+		render_data["data"] = data
+		render_data["js_data"] = ""
+		render_data["backlink"] = []string{}
+	}
+
+	return []string{render_data["data"].(string), render_data["js_data"].(string)}
+}

+ 25 - 0
route_go/route/tool/some_tool.go

@@ -0,0 +1,25 @@
+package tool
+
+import (
+	"crypto/sha256"
+	"encoding/hex"
+	"html/template"
+	"net/url"
+)
+
+func Sha224(data string) string {
+	hasher := sha256.New224()
+	hasher.Write([]byte(data))
+	hash_byte := hasher.Sum(nil)
+	hash_str := hex.EncodeToString(hash_byte)
+
+	return hash_str
+}
+
+func Url_parser(data string) string {
+	return url.QueryEscape(data)
+}
+
+func HTML_escape(data string) string {
+	return template.HTMLEscapeString(data)
+}

+ 33 - 0
route_go/windows_amd64.ps1

@@ -0,0 +1,33 @@
+$file_name = Read-Host "file_name "
+
+Write-Host "linux amd64"
+$env:GOOS = "linux"
+$env:GOARCH = "amd64"
+$env:CGO_ENABLED = 0
+go build $file_name.go
+Remove-Item ".\bin\$file_name.amd64.bin"
+Move-Item "opennamu" ".\bin\$file_name.amd64.bin"
+
+Write-Host "linux arm64"
+$env:GOOS = "linux"
+$env:GOARCH = "arm64"
+$env:CGO_ENABLED = 0
+go build $file_name.go
+Remove-Item ".\bin\$file_name.arm64.bin"
+Move-Item "opennamu" ".\bin\$file_name.arm64.bin"
+
+Write-Host "windows amd64"
+$env:GOOS = "windows"
+$env:GOARCH = "amd64"
+$env:CGO_ENABLED = 0
+go build $file_name.go
+Remove-Item ".\bin\$file_name.amd64.exe"
+Move-Item "opennamu.exe" ".\bin\$file_name.amd64.exe"
+
+Write-Host "windows arm64"
+$env:GOOS = "windows"
+$env:GOARCH = "arm64"
+$env:CGO_ENABLED = 0
+go build $file_name.go
+Remove-Item ".\bin\$file_name.arm64.exe"
+Move-Item "opennamu.exe" ".\bin\$file_name.arm64.exe"

+ 2 - 2
version.json

@@ -1,7 +1,7 @@
 {
     "beta" : {
-        "r_ver" : "v3.5.0-dev5",
-        "c_ver" : "3500374",
+        "r_ver" : "v3.5.0-dev36",
+        "c_ver" : "3500376",
         "s_ver" : "3500113"
     }
 }

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

@@ -110,6 +110,8 @@ details summary {
 
 .opennamu_comment_scroll {
     max-height: 500px;
+
+    white-space: pre-wrap;
     
     overflow: scroll;
     -ms-overflow-style: none;
@@ -269,12 +271,18 @@ code, pre {
     font-weight: initial;
 }
 
-@media ( max-width: 768px ) {
+@media(max-width: 768px) {
     .opennamu_popup_footnote {
         max-width: 100%;
     }
 }
 
+@media(max-width: 420px) {
+    .table_safe {
+        float: none !important;
+    }
+}
+
 hr {
     border: 0;
     border-top: 1px solid gainsboro;
@@ -403,6 +411,10 @@ s:hover, strike:hover, del:hover {
     list-style: none;
 }
 
+.opennamu_folding {
+    margin-top: 10px;
+}
+
 /* 이 부분 이하로는 레거시 */
 #topic_color {
     background: #bbeabb;

+ 49 - 6
views/main_css/js/func/func.js

@@ -78,12 +78,6 @@ class Accordion {
     }
 }
 
-window.addEventListener('DOMContentLoaded', function() {
-    document.querySelectorAll('details').forEach((el) => {
-        new Accordion(el);
-    });
-});
-
 function opennamu_do_id_check(data) {
     if(data.match(/\.|\:/)) {
         return 0;
@@ -130,4 +124,53 @@ function opennamu_do_trace_spread() {
             '<style>.opennamu_trace_button { display: none; } .opennamu_trace { white-space: pre-wrap; overflow-x: unset; text-overflow: unset; }</style>' +
         '' + document.getElementsByClassName('opennamu_trace')[0].innerHTML
     }
+}
+
+function opennamu_do_render(to_obj, data, name = '', do_type = '', option = '') {
+    let url;
+    if(do_type === '') {
+        url = "/api/render";
+    } else {
+        url = "/api/render/" + do_type;
+    }
+
+    fetch(url, {
+        method : 'POST',
+        headers : { 'Content-Type': 'application/x-www-form-urlencoded' },
+        body : new URLSearchParams({
+            'name' : name,
+            'data': data,
+            'option' : option
+        })
+    }).then(function(res) {
+        return res.json();
+    }).then(function(text) {
+        if(document.getElementById(to_obj)) {
+            if(text["data"]) {
+                document.getElementById(to_obj).innerHTML = text.data;
+                eval(text.js_data);
+            } else {
+                document.getElementById(to_obj).innerHTML = '';
+            }
+        }
+    });
+}
+
+function opennamu_xss_filter(str) {
+    return str.replace(/[&<>"'\/]/g, function(match) {
+        switch(match) {
+            case '&':
+                return '&amp;';
+            case '<':
+                return '&lt;';
+            case '>':
+                return '&gt;';
+            case "'":
+                return '&#x27;';
+            case '"':
+                return '&quot;';
+            case '/':
+                return '&#x2F;';
+        }
+    });
 }

+ 12 - 40
views/main_css/js/func/insert_user_info.js

@@ -1,18 +1,14 @@
 "use strict";
 
-function do_insert_user_info_sub(name, lang_data_list, lang_data = {}, for_a = 0) {
-    if(lang_data_list[for_a]) {
-        fetch("/api/lang/" + lang_data_list[for_a]).then(function(res) {
-            return res.json();
-        }).then(function(data) {
-            lang_data[lang_data_list[for_a]] = data['data'];
+function do_insert_user_info() {
+    if(document.getElementById('opennamu_get_user_info')) {
+        let name = document.getElementById('opennamu_get_user_info').innerHTML;
 
-            do_insert_user_info_sub(name, lang_data_list, lang_data, for_a + 1);
-        });
-    } else {
         fetch("/api/user_info/" + opennamu_do_url_encode(name)).then(function(res) {
             return res.json();
         }).then(function(data) {
+            let lang_data = data["language"];
+
             let get_data_auth = data['data']['auth'];
             if(get_data_auth === '0') {
                 get_data_auth = lang_data['ip'];
@@ -44,15 +40,17 @@ function do_insert_user_info_sub(name, lang_data_list, lang_data = {}, for_a = 0
                 
                 get_data_ban += lang_data['period'] + ' : ';
                 if(data['data']['ban']['period'] === '0') {
-                    get_data_ban += lang_data['limitless']; 
+                    get_data_ban += '~ ' + lang_data['limitless']; 
                 } else {
-                    get_data_ban += data['data']['ban']['period'];
+                    get_data_ban += '~ ' + data['data']['ban']['period'];
                 }
                 get_data_ban += '<br>';
                 
-                get_data_ban += lang_data['login_able'] + ' : ';
-                if(data['data']['ban']['login_able'] === '1') {
-                    get_data_ban += 'O'; 
+                get_data_ban += lang_data['option'] + ' : ';
+                if(data['data']['ban']['login_able'] === '2') {
+                    get_data_ban += lang_data['edit_request_able']; 
+                } else if(data['data']['ban']['login_able'] === '1') {
+                    get_data_ban += lang_data['login_able']; 
                 } else {
                     get_data_ban += 'X';
                 }
@@ -91,30 +89,4 @@ function do_insert_user_info_sub(name, lang_data_list, lang_data = {}, for_a = 0
     }
 }
 
-function do_insert_user_info() {
-    if(document.getElementById('opennamu_get_user_info')) {
-        let name = document.getElementById('opennamu_get_user_info').innerHTML;
-        let lang_data_list = [
-            'user_name',
-            'authority',
-            'state',
-            'member',
-            'normal',
-            'blocked',
-            'type',
-            'regex',
-            'period',
-            'limitless',
-            'login_able',
-            'why',
-            'band_blocked',
-            'ip',
-            'ban',
-            'level'
-        ];
-
-        do_insert_user_info_sub(name, lang_data_list);
-    }
-}
-
 do_insert_user_info();

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

@@ -1,3 +1,5 @@
+"use strict";
+
 function opennamu_change_comment(get_id) {
     const input = document.querySelector('#opennamu_comment_select');
     if(input !== null) {

+ 85 - 10
views/main_css/js/route/editor.js

@@ -170,8 +170,8 @@ class PlaceholderContentWidget {
     static ID = 'editor.widget.placeholderHint';
 
     constructor(placeholder, editor) {
-		this.placeholder = placeholder;
-		this.editor = 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
@@ -214,18 +214,93 @@ class PlaceholderContentWidget {
     }
 }
 
-function do_monaco_init(monaco_thema) {
-    require.config({ paths: { 'vs': 'https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.40.0/min/vs' }});
-    require.config({ 'vs/nls': { availableLanguages: { '*': 'ko' } }});
+function do_monaco_init(monaco_thema, markup = "") {
+    require.config({ paths: { 'vs' : 'https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.40.0/min/vs' }});
+    require.config({ 'vs/nls' : { availableLanguages: { '*' : 'ko' } }});
     require(["vs/editor/editor.main"], function () {
+        monaco.languages.register({ id : "namumark" });
+        monaco.languages.setMonarchTokensProvider("namumark", {
+            tokenizer : {
+                root : [
+                    [/\[/, "namumark-color"],
+                    [/\]/, "namumark-color"],
+                    
+                    [/\{/, "namumark-color"],
+                    [/\}/, "namumark-color"],
+
+                    [/'/, "namumark-color"],
+                    [/-/, "namumark-color"],
+                    [/~/, "namumark-color"],
+                    [/=/, "namumark-color"],
+                    [/_/, "namumark-color"],
+                    [/\^/, "namumark-color"],
+                    [/,/, "namumark-color"],
+
+                    [/\\/, "namumark-color"],
+                    [/\*/, "namumark-color"],
+                ],
+            },
+        });
+
+        let thema_set = [["namumark", "vs"], ["namumark-vs-dark", "vs-dark"]]
+        for(let for_a = 0; for_a < thema_set.length; for_a++) {
+            monaco.editor.defineTheme(thema_set[for_a][0], {
+                base : thema_set[for_a][1],
+                inherit : true,
+                rules : [
+                    { token : "namumark-color", foreground : "d94844" },
+                ],
+                colors : {
+                    "editor.foreground" : "",
+                },
+            });
+        }
+
         window.editor = monaco.editor.create(document.getElementById('opennamu_monaco_editor'), {
-            value: document.getElementById('opennamu_edit_textarea').value,
-            language: 'plaintext',
-            automaticLayout: true,
-            wordWrap: true,
-            theme: monaco_thema
+            value : document.getElementById('opennamu_edit_textarea').value,
+            language : 'namumark',
+            automaticLayout : true,
+            wordWrap : true,
+            theme : "namumark" + (monaco_thema === "" ? "" : "-" + monaco_thema)
         });
 
         new PlaceholderContentWidget(document.getElementById('opennamu_edit_textarea').placeholder, window.editor);
     });
+}
+
+function opennamu_do_editor_preview() {
+    do_sync_monaco_and_textarea();
+
+    const input = document.querySelector('#opennamu_edit_textarea');
+    if(input !== null) {
+        let doc_name = 'test';
+
+        const doc_name_input = document.querySelector('#opennamu_editor_doc_name');
+        if(doc_name_input !== null) {
+            doc_name = doc_name_input.value;
+        }
+
+        opennamu_do_render('opennamu_preview_area', input.value, doc_name);
+    }
+}
+
+function opennamu_do_editor_temp_save() {
+    do_sync_monaco_and_textarea();
+
+    const input = document.querySelector('#opennamu_edit_textarea');
+    if(input !== null) {
+        localStorage.setItem("key", input.value);
+    }
+}
+
+function opennamu_do_editor_temp_save_load() {
+    const data = localStorage.getItem("key");
+    if(data !== null) {
+        const input = document.querySelector('#opennamu_edit_textarea');
+        if(input !== null) {
+            input.value = data;
+        }
+        
+        do_textarea_to_manaco();
+    }
 }

+ 0 - 50
views/main_css/js/route/editor_sub.js

@@ -1,50 +0,0 @@
-function opennamu_do_editor_preview() {
-    do_sync_monaco_and_textarea();
-
-    const input = document.querySelector('#opennamu_edit_textarea');
-    if(input !== null) {
-        let doc_name = 'test';
-
-        const doc_name_input = document.querySelector('#opennamu_editor_doc_name');
-        if(doc_name_input !== null) {
-            doc_name = doc_name_input.value;
-        }
-
-        fetch("/api/render/" + (opennamu_do_url_encode(doc_name)), {
-            method : 'POST',
-            headers : { 'Content-Type': 'application/x-www-form-urlencoded' },
-            body : new URLSearchParams({
-                'data': input.value,
-            })
-        }).then(function(res) {
-            return res.json();
-        }).then(function(text) {
-            const preview = document.querySelector('#opennamu_preview_area');
-            if(preview !== null) {
-                preview.innerHTML = text.data;
-                eval(text.js_data);
-            }
-        });
-    }
-}
-
-function opennamu_do_editor_temp_save() {
-    do_sync_monaco_and_textarea();
-
-    const input = document.querySelector('#opennamu_edit_textarea');
-    if(input !== null) {
-        localStorage.setItem("key", input.value);
-    }
-}
-
-function opennamu_do_editor_temp_save_load() {
-    const data = localStorage.getItem("key");
-    if(data !== null) {
-        const input = document.querySelector('#opennamu_edit_textarea');
-        if(input !== null) {
-            input.value = data;
-        }
-        
-        do_textarea_to_manaco();
-    }
-}

+ 19 - 0
views/main_css/js/route/render.js

@@ -170,4 +170,23 @@ function opennamu_do_category_spread() {
             '<style>.opennamu_category_button { display: none; } .opennamu_category { white-space: pre-wrap; overflow-x: unset; text-overflow: unset; }</style>' +
         '' + document.getElementsByClassName('opennamu_render_complete')[0].innerHTML
     }
+}
+
+function opennamu_do_include(name, render_name, to_obj, option_obj) {
+    let option = {};
+    if(option_obj !== '') {
+        if(document.getElementById(option_obj)) {
+            option = document.getElementById(option_obj).innerHTML;
+            option = decodeURIComponent(option);
+        }
+    }
+
+    fetch("/api/raw/" + opennamu_do_url_encode(name)).then(function(res) {
+        return res.json();
+    }).then(function(data) {
+        if(data["data"]) {
+            opennamu_do_render(to_obj, data["data"], render_name, 'include', option);
+            document.getElementById(option_obj).style.display = "inline";
+        }
+    });
 }

+ 161 - 0
views/main_css/js/route/topic.js

@@ -1,3 +1,5 @@
+"use strict";
+
 function opennamu_do_remove_blind_thread() {
     const style = document.querySelector('#opennamu_remove_blind');
     if(style !== null) {
@@ -11,4 +13,163 @@ function opennamu_do_remove_blind_thread() {
             `;
         }
     }
+}
+
+function opennamu_thread_blind() {
+    let do_true = 0;
+    for(let for_a = 0; for_a < document.getElementsByClassName("opennamu_blind_button").length; for_a++) {
+        let id = document.getElementsByClassName("opennamu_blind_button")[for_a].id;
+        id = id.replace(/^opennamu_blind_/, '');
+        id = id.split('_');
+
+        let checked = document.getElementsByClassName("opennamu_blind_button")[for_a].checked;
+        if(checked) {
+            fetch("/thread/" + id[0] + '/comment/' + id[1] + '/blind', { method : 'GET' });
+            do_true = 1;
+        }
+    }
+
+    if(do_true === 1) {
+        history.go(0);
+    }
+}
+
+function opennamu_get_thread_ui(user_id, date, data, code, color = '', blind = '', add_style = '', topic_num = '') {
+    let color_b, class_b;
+    if(blind == 'O') {
+        color_b = data == '' ? 'opennamu_comment_blind' : 'opennamu_comment_blind_admin';
+        class_b = 'opennamu_comment_blind_js';
+    } else {
+        color_b = 'opennamu_comment_blind_not';
+        class_b = '';
+    }
+
+    let admin_check_box = ''
+    if(topic_num != '') {
+        admin_check_box = '<input type="checkbox" class="opennamu_blind_button" id="opennamu_blind_' + topic_num + '_' + code + '">';
+    }
+        
+    return `
+        <span class="` + class_b + `">
+            <table class="opennamu_comment" style="` + add_style + `">
+                <tr>
+                    <td class="opennamu_comment_color_` + color + `">
+                        ` + admin_check_box + `
+                        <a href="#thread_shortcut" id="` + code + `">#` + code + `</a>
+                        ` + user_id + `
+                        <span style="float: right;">` + date + `</span>
+                    </td>
+                </tr>
+                <tr>
+                    <td class="` + color_b + ` opennamu_comment_data_main" id="thread_` + code + `">
+                        ` + data + `
+                    </td>
+                </tr>
+            </table>
+            <hr class="main_hr">
+        </span>
+    `;
+}
+
+function opennamu_get_new_thread(topic_num = "", thread_num = "") {
+    let get_thread = setInterval(function() {
+        if(!document.getElementById('opennamu_default_thread_render_' + thread_num)) {
+            opennamu_get_thread(topic_num, "", thread_num);
+        } else {
+            opennamu_get_new_thread(topic_num, String(Number(thread_num) + 1));
+            clearInterval(get_thread);
+        }
+    }, 3000);
+}
+
+function opennamu_get_thread(topic_num = "", do_type = "", thread_num = "") {
+    let url, to_obj, color;    
+    if(do_type === "top") {
+        url = "/api/thread/" + topic_num + "/top";
+        to_obj = 'opennamu_top_thread';
+        color = 'red';
+    } else {
+        if(thread_num === "") {
+            url = "/api/thread/" + topic_num;
+        } else {
+            url = "/api/thread/" + topic_num + "/" + thread_num + "/" + thread_num;
+        }
+
+        to_obj = 'opennamu_main_thread';
+        color = 'default';
+    }
+
+    fetch(url).then(function(res) {
+        return res.json();
+    }).then(function(data) {
+        if(data["data"].length !== 0) {
+            let end_data = '';
+            let end_render = [];
+
+            let lang = data["language"];
+            data = data["data"];
+
+            let first = '';
+            for(let for_a = 0; for_a < data.length; for_a++) {
+                if(first === '') {
+                    first = data[for_a]["ip"];
+                }
+
+                let real_color = color;
+                if(color !== 'red') {
+                    if(data[for_a]["blind"] === '1') {
+                        real_color = 'blue';
+                    } else if(first === data[for_a]["ip"]) {
+                        real_color = 'green';
+                    } else {
+                        real_color = 'default';
+                    }
+                }
+
+                let date = '<a href="/thread/' + topic_num + '/comment/' + data[for_a]["id"] + '/tool">(' + lang["tool"] + ')</a> ' + data[for_a]["date"];
+                let render_data = data[for_a]["data"] !== "" ? data[for_a]["data"] : "[br]";
+
+                end_data += opennamu_get_thread_ui(
+                    data[for_a]["ip_render"], 
+                    date, 
+                    '<div class="opennamu_comment_scroll" id="opennamu_' + color + '_thread_render_' + data[for_a]["id"] + '">' + opennamu_xss_filter(render_data) + '</div>',
+                    data[for_a]["id"],
+                    real_color,
+                    data[for_a]["blind"],
+                    '',
+                    topic_num
+                )
+
+                end_render.push([
+                    render_data,
+                    data[for_a]["id"]
+                ]);
+            }
+
+            if(do_type === "" && thread_num === "") {
+                opennamu_get_new_thread(topic_num, String(Number(data[data.length - 1]["id"]) + 1));
+            }
+
+            document.getElementById(to_obj).innerHTML += end_data;
+
+            for(let for_a = 0; for_a < end_render.length; for_a++) {
+                let observer = new IntersectionObserver(entries => {
+                    entries.forEach(entry => {
+                        if(entry.isIntersecting) {
+                            opennamu_do_render(
+                                'opennamu_' + color + '_thread_render_' + end_render[for_a][1],
+                                end_render[for_a][0], 
+                                '',
+                                'thread'
+                            );
+
+                            observer.unobserve(entry.target);
+                        }
+                    });
+                });
+
+                observer.observe(document.getElementById('opennamu_' + color + '_thread_render_' + end_render[for_a][1]));
+            }
+        }
+    });
 }

+ 0 - 20
views/main_css/js/route/topic_sub.js

@@ -1,20 +0,0 @@
-"use strict";
-
-function opennamu_thread_blind() {
-    let do_true = 0;
-    for(let for_a = 0; for_a < document.getElementsByClassName("opennamu_blind_button").length; for_a++) {
-        let id = document.getElementsByClassName("opennamu_blind_button")[for_a].id;
-        id = id.replace(/^opennamu_blind_/, '');
-        id = id.split('_');
-
-        let checked = document.getElementsByClassName("opennamu_blind_button")[for_a].checked;
-        if(checked) {
-            fetch("/thread/" + id[0] + '/comment/' + id[1] + '/blind', { method : 'GET' });
-            do_true = 1;
-        }
-    }
-
-    if(do_true === 1) {
-        history.go(0);
-    }
-}

+ 63 - 0
views/main_css/js/route/view.js

@@ -0,0 +1,63 @@
+"use strict";
+
+function opennamu_view_w_raw(render = '') {
+    let name = "test";
+    if(document.getElementById('opennamu_editor_doc_name')) {
+        name = document.getElementById('opennamu_editor_doc_name').innerHTML;
+    }
+
+    let rev = "";
+    if(document.getElementById("opennamu_editor_rev")) {
+        rev = document.getElementById("opennamu_editor_rev").innerHTML;
+    }
+
+    let url = "";
+    if(rev !== '') {
+        url = "/api/raw_rev/" + rev + "/" + opennamu_do_url_encode(name);
+    } else {
+        url = "/api/raw/" + opennamu_do_url_encode(name);
+    }
+
+    fetch(url).then(function(res) {
+        return res.json();
+    }).then(function(data) {
+        if(document.getElementById("opennamu_edit_textarea")) {
+            if(data["data"]) {
+                document.getElementById("opennamu_edit_textarea").value = data["data"];
+            }
+
+            if(render === 'do') {
+                opennamu_view_w_raw_preview();
+            }
+        }
+    });
+}
+
+function opennamu_view_w_raw_preview() {
+    let name = "test";
+    if(document.getElementById('opennamu_editor_doc_name')) {
+        name = document.getElementById('opennamu_editor_doc_name').innerHTML;
+    }
+
+    let data = "";
+    if(document.getElementById('opennamu_edit_textarea')) {
+        data = document.getElementById('opennamu_edit_textarea').value;
+    }
+
+    opennamu_do_render('opennamu_preview_area', data, name);
+}
+
+function opennamu_view_w() {
+    let name = "test";
+    if(document.getElementById('opennamu_editor_doc_name')) {
+        name = document.getElementById('opennamu_editor_doc_name').innerHTML;
+    }
+
+    fetch("/api/raw/" + opennamu_do_url_encode(name)).then(function(res) {
+        return res.json();
+    }).then(function(data) {
+        if(data["data"]) {
+            opennamu_do_render('opennamu_preview_area', data["data"], name);
+        }
+    });
+}

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

@@ -5,6 +5,7 @@ html {
 body {
     font-family: 'SUIT', sans-serif;
     font-size: 14px;
+    font-feature-settings: "ss18";
 
     margin: 0;
 }
@@ -17,10 +18,12 @@ h1, h2, h3, h4, h5, h6 {
 
 select {
     font-family: 'SUIT', sans-serif;
+    font-feature-settings: "ss18";
 }
 
 textarea {
     font-family: 'SUIT', monospace;
+    font-feature-settings: "ss18";
 }
 
 h1.blank, h2.blank, h3.blank, h4.blank, h5.blank, h6.blank {

+ 2 - 2
views/ringo/index.html

@@ -8,12 +8,12 @@
             <title>{{imp[0]}} - {{imp[1][0]}}</title>
         {% endif %}
         {{imp[3][3]|safe}}
-        <link href="https://cdn.jsdelivr.net/gh/sunn-us/SUIT/fonts/static/woff2/SUIT.css" rel="stylesheet">
+        <link href="https://cdn.jsdelivr.net/gh/sun-typeface/SUIT/fonts/static/woff2/SUIT.css" rel="stylesheet">
         <script src="https://code.iconify.design/1/1.0.3/iconify.min.js"></script>
         <script src="/views/ringo/js/main.js.cache_v2"></script>
         <script src="/views/ringo/js/sidebar.js.cache_v1"></script>
         <script src="/views/ringo/js/skin_set.js.cache_v5"></script>
-        <link rel="stylesheet" href="/views/ringo/css/main.css.cache_v7">
+        <link rel="stylesheet" href="/views/ringo/css/main.css.cache_v8">
         {% if request.cookies.get('main_css_darkmode', '') == '1' %}
             {{imp[3][5]|safe}}
             <link rel="stylesheet" href="/views/ringo/css/dark.css.cache_v2">