Bladeren bron

Merge pull request #1089 from 2du/beta

문제 없겠지?
잉여개발기 (SPDV) 5 jaren geleden
bovenliggende
commit
ce4c7255c1
92 gewijzigde bestanden met toevoegingen van 2773 en 1893 verwijderingen
  1. 19 9
      app.py
  2. 9 3
      language/en-US.json
  3. 8 2
      language/ko-KR.json
  4. 10 12
      readme.md
  5. 1 0
      requirements.txt
  6. 1 1
      route/alarm.py
  7. 6 2
      route/api_raw.py
  8. 1 1
      route/api_recent_change.py
  9. 1 4
      route/api_sitemap.py
  10. 11 15
      route/api_skin_info.py
  11. 24 96
      route/api_topic_sub.py
  12. 48 21
      route/api_w.py
  13. 17 19
      route/applications.py
  14. 91 68
      route/edit.py
  15. 11 10
      route/edit_delete.py
  16. 1 1
      route/edit_many_delete.py
  17. 6 3
      route/edit_move.py
  18. 2 1
      route/edit_revert.py
  19. 2 5
      route/func_title_random.py
  20. 15 8
      route/func_upload.py
  21. 55 94
      route/give_acl.py
  22. 22 51
      route/give_admin_groups.py
  23. 14 10
      route/give_delete_admin_group.py
  24. 6 20
      route/give_history_add.py
  25. 17 22
      route/give_user_ban.py
  26. 12 5
      route/give_user_check.py
  27. 46 0
      route/give_user_check_delete.py
  28. 1 1
      route/inter_wiki.py
  29. 11 12
      route/list_acl.py
  30. 1 1
      route/list_admin.py
  31. 1 1
      route/list_admin_use.py
  32. 1 1
      route/list_give.py
  33. 1 1
      route/list_image_file.py
  34. 24 0
      route/list_long_page.py
  35. 1 1
      route/list_not_close_topic.py
  36. 1 1
      route/list_old_page.py
  37. 2 5
      route/list_please.py
  38. 10 12
      route/list_title_index.py
  39. 1 1
      route/list_user.py
  40. 4 20
      route/login.py
  41. 4 16
      route/login_2fa.py
  42. 107 122
      route/login_check_key.py
  43. 85 99
      route/login_need_email.py
  44. 11 16
      route/login_pw_change.py
  45. 39 83
      route/login_register.py
  46. 5 1
      route/main_image_view.py
  47. 10 7
      route/main_manager.py
  48. 6 4
      route/main_other.py
  49. 12 14
      route/main_views.py
  50. 36 69
      route/recent_changes.py
  51. 1 1
      route/recent_history_tool.py
  52. 6 12
      route/search_deep.py
  53. 1 1
      route/server_now_update.py
  54. 23 15
      route/setting.py
  55. 213 151
      route/tool/func.py
  56. 1 1
      route/tool/init.py
  57. 27 19
      route/tool/mark.py
  58. 39 25
      route/tool/namumark.py
  59. 0 136
      route/tool/set_mark/markdown.py
  60. 3 1
      route/tool/tool.py
  61. 28 55
      route/topic.py
  62. 3 3
      route/topic_admin.py
  63. 10 14
      route/topic_close_list.py
  64. 3 3
      route/topic_tool.py
  65. 1 1
      route/user_count_edit.py
  66. 26 23
      route/user_custom_head_view.py
  67. 4 3
      route/user_info.py
  68. 75 38
      route/user_setting.py
  69. 4 7
      route/user_tool.py
  70. 40 46
      route/view_diff_data.py
  71. 1 1
      route/view_down.py
  72. 18 24
      route/view_read.py
  73. 1 1
      route/view_xref.py
  74. 1 1
      route/vote.py
  75. 1 1
      route/vote_end.py
  76. 1 1
      route/watch_list.py
  77. 3 3
      version.json
  78. 249 53
      views/main_css/css/main.css
  79. 51 12
      views/main_css/css/sub/dark.css
  80. 34 17
      views/main_css/file/easter_egg.html
  81. 52 14
      views/main_css/js/load_editor.js
  82. 0 27
      views/main_css/js/load_preview.js
  83. 228 41
      views/main_css/js/load_skin_set.js
  84. 45 1
      views/main_css/js/load_something.js
  85. 104 109
      views/main_css/js/load_topic.js
  86. 0 0
      views/main_css/js/render_markdown.js
  87. 69 34
      views/main_css/js/render_namumark.js
  88. 564 0
      views/main_css/js/render_onmark.js
  89. 1 9
      views/marisa/css/main.css
  90. 3 3
      views/marisa/index.html
  91. 2 8
      views/marisa/js/main.js
  92. 7 7
      views/marisa/js/skin_set.js

+ 19 - 9
app.py

@@ -118,11 +118,11 @@ if set_data['db_type'] == 'mysql':
     curs = conn.cursor()
 
     try:
-        curs.execute(db_change('create database ? default character set utf8mb4;')%pymysql.escape_string(set_data['db']))
+        curs.execute(db_change('create database ' + set_data['db'] + ' default character set utf8mb4;'))
     except:
         pass
-
-    curs.execute(db_change('use ?')%pymysql.escape_string(set_data['db']))
+    
+    conn.select_db(set_data['db'])
 else:
     conn = sqlite3.connect(set_data['db'] + '.db')
     curs = conn.cursor()
@@ -131,7 +131,7 @@ load_conn(conn)
 
 # DB init
 create_data = {}
-create_data['data'] = ['title', 'data']
+create_data['data'] = ['title', 'data', 'type']
 create_data['cache_data'] = ['title', 'data', 'id']
 create_data['history'] = ['id', 'title', 'data', 'date', 'ip', 'send', 'leng', 'hide', 'type']
 create_data['rc'] = ['id', 'title', 'date', 'type']
@@ -142,14 +142,13 @@ create_data['user_application'] = ['id', 'pw', 'date', 'encode', 'question', 'an
 create_data['topic'] = ['id', 'data', 'date', 'ip', 'block', 'top', 'code']
 create_data['rb'] = ['block', 'end', 'today', 'blocker', 'why', 'band', 'login', 'ongoing']
 create_data['back'] = ['title', 'link', 'type']
-create_data['custom'] = ['user', 'css']
 create_data['other'] = ['name', 'data', 'coverage']
 create_data['alist'] = ['name', 'acl']
 create_data['re_admin'] = ['who', 'what', 'time']
 create_data['alarm'] = ['name', 'data', 'date']
 create_data['ua_d'] = ['name', 'ip', 'ua', 'today', 'sub']
 create_data['scan'] = ['user', 'title', 'type']
-create_data['acl'] = ['title', 'decu', 'dis', 'view', 'why']
+create_data['acl'] = ['title', 'data', 'type']
 create_data['html_filter'] = ['html', 'kind', 'plus', 'plus_t']
 create_data['vote'] = ['name', 'id', 'subject', 'data', 'user', 'type', 'acl']
 for i in create_data:
@@ -159,7 +158,7 @@ for i in create_data:
         try:
             curs.execute(db_change('create table ' + i + '(test longtext)'))
         except:
-            curs.execute(db_change("alter table " + i + " add test longtext default ''"))
+            curs.execute(db_change("alter table " + i + " add test longtext"))
 
 setup_tool = 0
 try:
@@ -179,7 +178,10 @@ if setup_tool != 0:
             try:
                 curs.execute(db_change('select ' + create + ' from ' + create_table + ' limit 1'))
             except:
-                curs.execute(db_change("alter table " + create_table + " add " + create + " longtext default ''"))
+                try:
+                    curs.execute(db_change("alter table " + create_table + " add " + create + " longtext default ''"))
+                except:
+                    curs.execute(db_change("alter table " + create_table + " add " + create + " longtext"))
 
     if setup_tool == 1:
         update(int(ver_set_data[0][0]), set_data)
@@ -537,6 +539,10 @@ def login_pw_change():
 @app.route('/check/<name>')
 def give_user_check(name = None):
     return give_user_check_2(conn, name)
+    
+@app.route('/check_delete', methods=['POST', 'GET'])
+def give_user_check_delete():
+    return give_user_check_delete_2(conn)
 
 @app.route('/register', methods=['POST', 'GET'])
 def login_register():
@@ -605,6 +611,10 @@ def func_upload():
 def user_info():
     return user_info_2(conn)
 
+@app.route('/<regex("long_page|short_page"):tool>')
+def list_long_page(tool = 'long_page'):
+    return list_long_page_2(conn, tool)
+
 @app.route('/<regex("watch_list|star_doc"):tool>')
 def watch_list(tool = 'star_doc'):
     return watch_list_2(conn, tool)
@@ -742,4 +752,4 @@ if __name__ == "__main__":
     http_server = tornado.httpserver.HTTPServer(tornado.wsgi.WSGIContainer(app))
     http_server.listen(int(server_set['port']), address = server_set['host'])
 
-    tornado.ioloop.IOLoop.instance().start()
+    tornado.ioloop.IOLoop.instance().start()

+ 9 - 3
language/en-US.json

@@ -267,6 +267,7 @@
                 "requires_approval" : "Requires approval for register",
                 "approval_question": "Registeration questions",
                 "backup_where" : "Backup location",
+                "ua_get_off" : "Turn off members information collection",
             "_comment_2.2.3_" : "Text",
                 "register_text" : "Terms of sign-up",
                 "non_login_alert" : "Non-login alert",
@@ -282,6 +283,7 @@
                 "error_404" : "Missing document notice",
                 "edit_help" : "Editing textarea phrase",
                 "upload_help" : "File upload phrase",
+                "upload_default" : "File upload other Default",
             "_comment_2.2.4_" : "Google",
                 "recaptcha" : "reCAPTCHA",
                 "smtp_setting" : "Email SMTP setting",
@@ -300,6 +302,8 @@
             "all_document_list" : "All document(s) list",
             "watchlist" : "Watchlist",
             "image_file_list" : "Image file(s) list",
+            "short_page" : "Short page(s) list",
+            "long_page" : "Long page(s) list",
             "_comment_2.3.1_" : "ACL document list",
                 "acl_document_list" : "ACL document(s) list",
                 "acl_required" : "Required ACL",
@@ -334,7 +338,7 @@
             "before_acl" : "Only those who have edited this document before",
             "ban_acl" : "Include blocked users",
             "ban_admin_acl" : "Blocked users and administrators",
-            "30_day_acl" : "Only members 30 days after register",
+            "30_day_acl" : "Only members 30 days after sign up",
             "_comment_2.6_1_" : "Set",
                 "document_acl" : "Document ACL",
                 "discussion_acl" : "Discussion(s) ACL",
@@ -372,7 +376,7 @@
         "oauth_settings_not_found" : "The administrator has not provided any data about using this feature.",
         "oauth_disabled" : "The administrator has disabled this feature.",
         "http_warring" : "Warning: If you are not on HTTPS connection, Your information can be leaked. We won't response to that.",
-        "user_head_warring" : "User <HEAD> will be deleted if you close the browser or when you sign in.",
+        "user_head_warring" : "User data will be deleted if you close the browser or when you sign in.",
         "no_login_warring" : "You are not logged in. The IP address will be logged when editing or discussing with non-login.",
         "user_reset_sign" : "Your account information has changed like this.",
         "update_warring" : "Manual updates are recommended if your version is 0.2 or lower than the latest version. For Windows, the contents of the route folder disappear.",
@@ -419,5 +423,7 @@
             "watchlist_overflow_error": "You cannot add more than ten documents.",
             "copyright_disagreed" : "You have to agree copyright noticement to contribute",
             "email_send_error" : "Email transfer failed.",
-            "restart_fail_error" : "Restart failed. Please use manual restart."
+            "restart_fail_error" : "Restart failed. Please use manual restart.",
+            "same_email_error" : "There are users using the same email.",
+            "input_email_error" : "There is a problem with the input value."
 }

+ 8 - 2
language/ko-KR.json

@@ -271,7 +271,7 @@
     "other": "기타",
     "edit": "편집",
     "open_discussion_list": "열린 토론 목록",
-    "user_head_warring": "비로그인시 브라우저를 닫거나 로그인시 사용자가 지정한 <HEAD>는 삭제됩니다.",
+    "user_head_warring": "비로그인시 브라우저를 닫거나 로그인시 사용자가 지정한 정보는 삭제됩니다.",
     "email_required": "이메일 필요",
     "1_day": "1일",
     "regex_error": "정규표현식에 오류가 있습니다.",
@@ -394,5 +394,11 @@
     "2fa_password" : "2차 비밀번호",
     "2fa_password_change" : "2차 비밀번호 변경",
     "vote_acl" : "투표 ACL",
-    "upload_help" : "파일 올리기 문구"
+    "upload_help" : "파일 올리기 문구",
+    "upload_default" : "파일 기타란 기본값",
+    "same_email_error" : "동일한 이메일을 사용하는 사용자가 있습니다.",
+    "input_email_error" : "입력 값에 문제가 있습니다.",
+    "short_page" : "짧은 문서 목록",
+    "long_page" : "긴 문서 목록",
+    "ua_get_off" : "가입자 정보 수집 끄기"
 }

+ 10 - 12
readme.md

@@ -5,7 +5,7 @@
 
 ![](https://raw.githubusercontent.com/2du/openNAMU/beta/.github/logo.png)
 
-오픈나무는 파이썬 기반의 위키 엔진입니다. 파이썬과 그 의존성 모듈만 설치하면 사용할 수 있으며, 코드를 직접 수정하여 좀 더 주제에 특화된 위키를 만들 수 있습니다.
+오픈나무는 파이썬 기반의 위키 엔진입니다.
 
 ### 목차
  * [시작하기](#시작하기)
@@ -18,21 +18,21 @@
 ## 시작하기
 오픈나무는 파이썬 환경에서 동작하는 파이썬 애플리케이션으로, 파이썬 환경을 필요로 합니다.
 
-쉬운 오픈나무 설치를 위해 오픈나무 가이드를 따로 생성해두었으며, [이곳](https://2du.pythonanywhere.com/w/%EC%84%A4%EC%B9%98%EB%B2%95)에서 확인하실 수 있습니다.
+[여기](https://2du.pythonanywhere.com/w/설치법)를 눌러 설치 가이드를 볼 수 있습니다.
 
-## 클론
+### 클론
 아래 명령을 터미널(명령 프롬프트)에 입력하여 본 리포지토리를 클론할 수 있습니다.
- * `git clone -b stable https://github.com/2du/openNAMU.git`
- * `git clone -b beta https://github.com/2du/openNAMU.git`
- * `git clone -b dev https://github.com/2du/openNAMU.git`
+ * 일반: `git clone -b stable https://github.com/2du/openNAMU.git`
+ * 베타: `git clone -b beta https://github.com/2du/openNAMU.git`
+ * 개발: `git clone -b dev https://github.com/2du/openNAMU.git`
 
 ## 기여
-오픈나무에는 검증되지 않은 몇가지 버그가 존재할 수 있습니다. 당신의 오픈나무 사용과 버그 발견은 오픈나무의 발전을 돕습니다. [(이슈 생성하기)](https://github.com/2du/openNAMU/issues/new)
+오픈나무에는 확인되지 않은 버그가 존재할 수 있습니다. 이를 보고해주시면 오픈나무의 발전을 도울 수 있습니다. [여기](https://github.com/2du/openNAMU/issues/new)를 눌러 버그를 보고해주세요.
 
-오픈나무는 완전한 오픈소스 프로젝트입니다. 새로운 기능을 추가하고 Pull Request를 생성해보세요. [(Pull Request 생성하기)](https://github.com/2du/openNAMU/compare)
+오픈나무는 오픈소스 프로젝트입니다. 원한다면 직접 코드를 수정하고 Pull Request를 보낼 수 있습니다.
 
 ## 라이선스
-오픈나무 프로젝트는 [BSD 3-Clause License](./LICENSE)(이하 이용허락)의 보호를 받고 있으며, 오픈나무 프로젝트를 사용하고자 한다면 라이선스를 준수해야 합니다. 본 이용허락를 위반할 경우 개발자는 DMCA Takedown 등 관련 제재를 관계자에게 요청할 권리가 있으며, 그 책임은 모두 이용허락 위반 사용자에게 있습니다. 자세한 내용은 문서를 참고하세요.
+오픈나무 프로젝트는 [BSD 3-Clause License](./LICENSE)의 보호를 받고 있으며, 오픈나무 프로젝트를 사용하고자 한다면 라이선스를 준수해야 합니다. 본 라이선스를 위반할 경우 법적인 조치가 취해질 수 있습니다. 자세한 내용은 문서를 참고하세요.
 
 ### 포함된 외부 프로젝트
  * Quotes icon - [Dave Gandy](http://www.flaticon.com/free-icon/quote-left_25672)
@@ -40,9 +40,6 @@
  * Numerical expression - [MathJax](https://www.mathjax.org/)
  * Handling Keyboard Shortcuts [shortcut.js](http://www.openjs.com/scripts/events/keyboard_shortcuts/)
 
-### 기여자 목록
- * [참고](https://github.com/2DU/openNAMU/graphs/contributors)
-
 ### 도움을 주신 분들
  * [Team Croatia](https://github.com/TeamCroatia)
  * Basix
@@ -56,3 +53,4 @@
 ## 기타
  * 첫 가입자에게 소유자 권한이 부여됩니다.
  * [테스트 서버](http://2du.pythonanywhere.com)
+ * [기여자 목록](https://github.com/2DU/openNAMU/graphs/contributors)

+ 1 - 0
requirements.txt

@@ -3,5 +3,6 @@ flask-Reggie
 tornado
 requests
 pymysql
+Pillow
 diff-match-patch
 pysha3; python_version < "3.6"

+ 1 - 1
route/alarm.py

@@ -9,7 +9,7 @@ def alarm_2(conn):
     else:
         sql_num = 0
 
-    data = '<ul>'
+    data = '<ul class="inside_ul">'
 
     curs.execute(db_change("select data, date from alarm where name = ? order by date desc limit ?, 50"), [ip_check(), sql_num])
     data_list = curs.fetchall()

+ 6 - 2
route/api_raw.py

@@ -4,11 +4,15 @@ def api_raw_2(conn, name):
     curs = conn.cursor()
 
     if acl_check(name, 'render') != 1:
-        curs.execute(db_change("select data from data where title = ?"), [name])
+        rev = flask.request.args.get('num', '')
+        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:
             json_data = { "title" : name, "data" : render_set(title = name, data = data[0][0], s_data = 1) }
 
             return flask.jsonify(json_data)
         
-    return flask.jsonify({})
+    return flask.jsonify({})

+ 1 - 1
route/api_recent_change.py

@@ -10,7 +10,7 @@ def api_recent_change_2(conn):
     admin = admin_check(6)
     get_title = ''
 
-    curs.execute(db_change('select id, title from rc order by date desc'))
+    curs.execute(db_change('select id, title from rc where type = "" order by date desc'))
     for i in curs.fetchall():
         if repeat_ok == '1' or i[1] != get_title:
             get_title = i[1]

+ 1 - 4
route/api_sitemap.py

@@ -8,14 +8,11 @@ def api_sitemap_2(conn):
             '<?xml version="1.0" encoding="UTF-8"?>\n' + \
             '<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">\n' + \
         ''
+        domain = load_domain()
 
         curs.execute(db_change("select title from data"))
         all_data = curs.fetchall()
 
-        curs.execute(db_change("select data from other where name = 'domain'"))
-        domain = curs.fetchall()
-        domain = domain[0][0] if domain and domain[0][0] != '' else flask.request.host_url
-
         len_all_data = len(all_data)
         count = int(len_all_data / 30000)
         other_count = len_all_data % 30000

+ 11 - 15
route/api_skin_info.py

@@ -2,12 +2,8 @@ from .tool.func import *
 
 def api_skin_info_2(conn, name):
     curs = conn.cursor()
-
-    if name == '':
-        name = skin_check()
-    else:
-        name = './views/' + name + '/index.html'
-
+    name = skin_check() if name == '' else './views/' + name + '/index.html'
+    
     if not flask.request.args.get('all', None):
         json_address = re.sub(r"(((?!\.|\/).)+)\.html$", "info.json", name)
         try:
@@ -40,14 +36,12 @@ def api_skin_info_2(conn, name):
 
                 if "info_link" in json_data:
                     info_link = json_data["info_link"]
-                    get_num = 1
                 elif json_data["name"] in d_link_data:
                     info_link = d_link_data[json_data["name"]]
-                    get_num = 1
                 else:
-                    get_num = 0
+                    info_link = 0
 
-                if get_num == 1:
+                if info_link != 0:
                     try:
                         get_data = urllib.request.urlopen(info_link)
                     except:
@@ -56,12 +50,14 @@ def api_skin_info_2(conn, name):
                     if get_data and get_data.getcode() == 200:
                         try:
                             get_data = json.loads(get_data.read().decode())
-                            if "skin_ver" in get_data:
-                                json_data = {**json_data, **{ "lastest_version" : {
-                                    "skin_ver" : json_data["skin_ver"]
-                                }}}
                         except:
-                            pass
+                            get_data = {}
+                        
+                        if "skin_ver" in get_data:
+                            json_data = {**json_data, **{ "lastest_version" : {
+                                "skin_ver" : get_data["skin_ver"]
+                            }}}
+                        
 
                 a_data = {**a_data, **{ i : json_data }}
 

+ 24 - 96
route/api_topic_sub.py

@@ -18,103 +18,31 @@ def api_topic_sub_2(conn, topic_num):
 
     data = curs.fetchall()
     if data:
-        json_data = {}
+        data_a = {}
         admin = admin_check(3)
 
-        if flask.request.args.get('render', None):
-            all_ip = ip_pas([i[3] for i in data])
-            for i in data:
-                ip = all_ip[i[3]]
-
-                if i[4] != 'O':
-                    t_data_f = i[1]
-                    b_color = 'toron_color'
-                else:
-                    t_data_f = ''
-                    b_color = 'toron_color_not'
-
-                    ip += ' <a href="/admin_log?search=blind%20(code%20' + topic_num + '#' + i[0] + '">(B)</a>'
-
-                    if admin == 1:
-                        ip += ' <a href="/thread/' + topic_num + '/raw/' + i[0] + '">(R)</a>'
-
-                if i[0] == '1':
-                    s_user = i[3]
-                else:
-                    if flask.request.args.get('num', None):
-                        curs.execute(db_change("select ip from topic where code = ? order by id + 0 asc limit 1"), [topic_num])
-                        g_data = curs.fetchall()
-                        if g_data:
-                            s_user = g_data[0][0]
-                        else:
-                            s_user = ''
-
-                if flask.request.args.get('top', None):
-                    t_color = 'toron_color_red'
-                elif i[3] == s_user and i[5] != '1':
-                    t_color = 'toron_color_green'
-                elif i[5] == '1':
-                    t_color = 'toron_color_blue'
-                else:
-                    t_color = 'toron_color'
-
-                if admin == 1 or b_color != 'toron_color_not':
-                    ip += ' <a href="/thread/' + topic_num + '/admin/' + i[0] + '">(' + load_lang('discussion_tool') + ')</a>'
-
-                if t_data_f == '':
-                    t_data_f = '[br]'
-
-                t_data_f = render_set(data = t_data_f, num = 2, include = 'topic_' + i[0], acl = get_acl)
-                t_plus_data = t_data_f[1]
-                t_data_f = t_data_f[0]
-
-                t_data_f = re.sub(
-                    r'&lt;topic_a&gt;((?:(?!&lt;\/topic_a&gt;).)+)&lt;\/topic_a&gt;', 
-                    '<a href="\g<1>">\g<1></a>', 
-                    t_data_f
-                )
-                t_data_f = re.sub(
-                    r'&lt;topic_call&gt;@((?:(?!&lt;\/topic_call&gt;).)+)&lt;\/topic_call&gt;', 
-                    '<a href="/w/user:\g<1>">@\g<1></a>', 
-                    t_data_f
-                )
-
-                all_data = '' + \
-                    '<table id="toron">' + \
-                        '<tbody>' + \
-                            '<tr>' + \
-                               '<td id="' + t_color + '">' + \
-                                    '<a href="javascript:void(0);" id="' + i[0] + '">#' + i[0] + '</a> ' + ip + ' <span style="float: right;">' + i[2] + '</span>' + \
-                                '</td>' + \
-                            '</tr>' + \
-                            '<tr>' + \
-                                '<td id="' + b_color + '">' + \
-                                    '<div id="topic_scroll">' + t_data_f + '</div>' + \
-                                '</td>' + \
-                            '</tr>' + \
-                        '</tbody>' + \
-                    '</table>' + \
-                    '<hr class="main_hr">' + \
-                ''
-
-                json_data[i[0]] = {
-                    "data" : all_data,
-                    "plus_data" : t_plus_data
-                }
-        else:
-            for i in data:
-                if i[4] != 'O' or (i[4] == 'O' and admin == 1):
-                    t_data_f = i[1]
-                else:
-                    t_data_f = '(B)'
-
-                json_data[i[0]] = {
-                    "data" : t_data_f,
-                    "date" : i[2],
-                    "ip" : ip_pas(i[3], 1),
-                    "block" : i[4],
-                }
-
-        return flask.jsonify(json_data)
+        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)
+        }
+            
+        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 ''
+            data_a[i[0]] = {
+                "data" : data_v,
+                "date" : i[2],
+                "ip" : ip_a_2[i[3]],
+                "blind" : i[4],
+                
+                "ip_pas" : ip_a[i[3]],
+                "data_pas" : render_set(data = data_v, num = 2, include = 'topic_' + i[0], acl = get_acl)
+            }
+
+        return flask.jsonify(data_a)
     else:
         return flask.jsonify({})

+ 48 - 21
route/api_w.py

@@ -3,43 +3,70 @@ from .tool.func import *
 def api_w_2(conn, name):
     curs = conn.cursor()
 
-    if flask.request.args.get('exist', None):
+    data_arg_exist = flask.request.args.get('exist', '')
+    if data_arg_exist != '':
         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 acl_check(name, 'render') != 1:
             if flask.request.method == 'POST':
-                g_data = render_set(title = name, data = flask.request.form.get('data', ''), num = 2)
+                data_org = flask.request.form.get('data', '')
+                data_pas = render_set(
+                    title = name, 
+                    data = data_org, 
+                    num = 2
+                )
 
-                return flask.jsonify({ "title" : name, "data" : g_data[0], "js_data" : g_data[1] })
+                return flask.jsonify({
+                    "data" : data_pas[0], 
+                    "js_data" : data_pas[1]
+                })
             else:
-                curs.execute(db_change("select data from data where title = ?"), [name])
+                data_arg_rev = flask.request.args.get('num', '')
+                if data_arg_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:
-                    if flask.request.args.get('include', 'include_1'):
-                        json_data = data[0][0]
+                    name_org = flask.request.args.get('name_org', '')
+                    if name_org == '':
+                        name_org = name
+                        
+                    json_data = data[0][0]
+                    
+                    include_data = flask.request.args.get('include', '')
+                    if include_data != '':
+                        get_all_change_1 = []
+                        find_replace_moment = re.findall(r'(@([^=@]+)=([^=@]+)@|@([^=@]+)@)', json_data)
+                        for i in find_replace_moment:
+                            if i[1] != '':
+                                get_all_change_1 += [['@' + i[1] + '@', i[2]]]
 
-                        get_all_change_1 = [('@' + i[0] + '@', i[1]) for i in re.findall(r'@([^=]+)=([^@]+)@', json_data)]
-                        json_data = re.sub(r'@(?P<in>[^=]+)=([^@]+)@', '@\g<in>@', json_data)
+                                json_data = json_data.replace(i[0], '@' + i[1] + '@', 1)
+                            else:
+                                json_data = json_data.replace(i[0], '@' + i[3] + '@', 1)
 
                         get_all_change_2 = re.findall(r'(@(?:[^@]*)@),([^,]*),', flask.request.args.get('change', '')) + get_all_change_1
                         for i in get_all_change_2:
                             json_data = json_data.replace(
                                 i[0].replace('<amp>', '&'), 
-                                i[1].replace('<amp>', '&').replace('<comma>', ',')
+                                i[1].replace('<amp>', '&').replace('<comma>', ','), 
+                                1
                             )
+                        
+                    data_pas = render_set(
+                        title = name_org, 
+                        data = json_data, 
+                        num = 2, 
+                        include = include_data
+                    )
 
-                        g_data = render_set(title = name, data = json_data, num = 2, include = flask.request.args.get('include', 'include_1'))
-                    else:
-                        json_data = g_data[0]
-
-                        g_data = render_set(title = name, data = json_data, num = 2)
+                    return flask.jsonify({
+                        "data" : data_pas[0], 
+                        "js_data" : data_pas[1]
+                    })
 
-                    return flask.jsonify({ "title" : name, "data" : g_data[0], "js_data" : g_data[1] })
-                else:
-                    return flask.jsonify({})
-        else:
-            return flask.jsonify({})
+    return flask.jsonify({})

+ 17 - 19
route/applications.py

@@ -4,9 +4,8 @@ def applications_2(conn):
     curs = conn.cursor()
 
     div = ''
-    admin = admin_check()
 
-    if admin != 1:
+    if admin_check() != 1:
         return re_error('/ban')
 
     curs.execute(db_change('select data from other where name = "requires_approval"'))
@@ -26,10 +25,13 @@ def applications_2(conn):
                 email = application[5]
                 if not question:
                     question = ''
+
                 if not answer:
                     answer = ''
+                
                 if not email:
                     email = ''
+                
                 div += '''
                     <form method=\"post\">
                         <table>
@@ -41,7 +43,7 @@ def applications_2(conn):
                                     <td>''' + load_lang('application_time') + '''</td><td>''' + application[1] + '''</td>
                                 </tr>
                                 <tr>
-                                    <td>''' + load_lang('approval_question') + '''</td><td>''' + question + '''</td>
+                                    <td>''' + load_lang('approval_question') + '''</td><td>''' + html.escape(question) + '''</td>
                                 </tr>
                                 <tr>
                                     <td>''' + load_lang('answer') + '''</td><td>''' + html.escape(answer) + '''</td>
@@ -62,9 +64,17 @@ def applications_2(conn):
                 '''
         else:
             div += load_lang('no_applications_now')
+
+        return easy_minify(flask.render_template(skin_check(),
+            imp = [load_lang('application_list'), wiki_set(), custom(), other2([0, 0])],
+            data = div,
+            menu = [['other', load_lang('return')]]
+        ))
     else:
         if flask.request.form.get('approve', '') != '':
-            curs.execute(db_change('select id, pw, date, encode, question, answer, ip, ua, email from user_application where token = ?'), [flask.request.form.get('approve', '')])
+            curs.execute(db_change('select id, pw, date, encode, question, answer, ip, ua, email from user_application where token = ?'), [
+                flask.request.form.get('approve', '')
+            ])
             application = curs.fetchall()
             if not application:
                 return re_error('/error/26')
@@ -83,26 +93,14 @@ def applications_2(conn):
             ])
             curs.execute(db_change("insert into user_set (name, id, data) values ('approval_question', ?, ?)"), [application[0], application[4]])
             curs.execute(db_change("insert into user_set (name, id, data) values ('approval_question_answer', ?, ?)"), [application[0], application[5]])
-            curs.execute(db_change("insert into ua_d (name, ip, ua, today, sub) values (?, ?, ?, ?, '')"), [
-                application[0], 
-                application[6], 
-                application[7], 
-                application[2]
-            ])
+            ua_plus(application[0], application[6], application[7], application[2])
             if application[8] and application[8] != '':
                 curs.execute(db_change("insert into user_set (name, id, data) values ('email', ?, ?)"), [application[0], application[8]])
+            
             curs.execute(db_change('delete from user_application where token = ?'), [flask.request.form.get('approve', '')])
- 
-
             conn.commit()
         elif flask.request.form.get('decline', '') != '':
             curs.execute(db_change('delete from user_application where token = ?'), [flask.request.form.get('decline', '')])
             conn.commit()
 
-        return redirect('/applications')
-
-    return easy_minify(flask.render_template(skin_check(),
-        imp = [load_lang('application_list'), wiki_set(), custom(), other2([0, 0])],
-        data = div,
-        menu = [['other', load_lang('return')]]
-    ))
+        return redirect('/applications')

+ 91 - 68
route/edit.py

@@ -29,12 +29,14 @@ def edit_2(conn, name):
     if acl_check(name) == 1:
         return re_error('/ban')
     
+    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'
+
     edit_repeat = 0
     if flask.request.method == 'POST':
         edit_repeat = 1
-        curs.execute(db_change("select id from history where title = ? order by id + 0 desc"), [name])
-        old = curs.fetchall()
-        if old and flask.request.form.get('ver', '') != old[0][0]:
+        if flask.request.form.get('ver', '') != doc_ver:
             edit_repeat = 2
     
     if edit_repeat == 1:
@@ -48,10 +50,6 @@ def edit_2(conn, name):
 
         today = get_time()
         content = flask.request.form.get('content', '').replace('\r\n', '\n')
-        o_content = flask.request.form.get('o_content', '').replace('\r\n', '\n')
-
-        if o_content == content:
-            return redirect('/w/' + url_pas(name))
         
         if edit_filter_do(content) == 1:
             return re_error('/error/21')
@@ -90,11 +88,7 @@ def edit_2(conn, name):
 
         curs.execute(db_change("select user from scan where title = ? and type = ''"), [name])
         for scan_user in curs.fetchall():
-            curs.execute(db_change("insert into alarm (name, data, date) values (?, ?, ?)"), [
-                scan_user[0],
-                ip + ' | <a href="/w/' + url_pas(name) + '">' + name + '</a> | Edit', 
-                today
-            ])
+            add_alarm(scan_user[0], ip + ' | <a href="/w/' + url_pas(name) + '">' + name + '</a> | Edit')
                 
         history_plus(
             name,
@@ -116,66 +110,49 @@ def edit_2(conn, name):
         
         conn.commit()
         
-        return redirect('/w/' + url_pas(name))
+        return redirect('/w/' + url_pas(name) + (('#edit_load_' + str(section)) if section else ''))
     else:
-        curs.execute(db_change("select data, id from history where title = ? order by id + 0 desc"), [name])
-        old = curs.fetchall()
-        if old:
-            if section:
-                data = html.escape('\n' + old[0][0].replace('\r\n', '\n'))
-                data = re.sub(r'\n(?P<in>={1,6})', '<br>\g<in>', data)
-
-                section_data = re.findall(r'<br>((?:(?:(?!<br>).)*\n*)*)', data)
-                if len(section_data) >= section:
-                    data = html.unescape(section_data[section - 1])
-                else:
-                    return redirect('/edit/' + url_pas(name))
+        editor_top_text = ''
+        if edit_repeat != 2:
+            load_title = flask.request.args.get('plus', None)
+            if load_title:
+                curs.execute(db_change("select data from data where title = ?"), [load_title])
+                get_data = curs.fetchall()
+                data = get_data[0][0] if get_data else ''
             else:
-                data = old[0][0].replace('\r\n', '\n')
+                curs.execute(db_change("select data, id from history where title = ? order by id + 0 desc"), [name])
+                old = curs.fetchall()
+                old = old if old else [['']]
+                if section:
+                    data = html.escape('\n' + old[0][0].replace('\r\n', '\n'))
+                    data = re.sub(r'\n(?P<in>={1,6})', '<br>\g<in>', data)
+
+                    section_data = re.findall(r'<br>((?:(?:(?!<br>).)*\n*)*)', data)
+                    if len(section_data) >= section:
+                        data = html.unescape(section_data[section - 1])
+                    else:
+                        return redirect('/edit/' + url_pas(name))
+                else:
+                    data = old[0][0].replace('\r\n', '\n')
+                    editor_top_text += '<a href="/manager/15?plus=' + url_pas(name) + '">(' + load_lang('load') + ')</a> '
         else:
-            data = ''
-            
-        data_old = data
-        if edit_repeat == 2:
             data = flask.request.form.get('content', '')
-        
             warring_edit = load_lang('exp_edit_conflict') + ' '
 
             if flask.request.form.get('ver', '0') == '0':
-                warring_edit += '<a href="/raw/' + url_pas(name) + '">(r' + old[0][1] + ')</a>'
+                warring_edit += '<a href="/raw/' + url_pas(name) + '">(r' + doc_ver + ')</a>'
             else:
                 warring_edit += '' + \
-                    '<a href="/diff/' + url_pas(name) + '?first=' + flask.request.form.get('ver', '1') + '&second=' + old[0][1] + '">(r' + old[0][1] + ')</a>' + \
+                    '<a href="/diff/' + url_pas(name) + '?first=' + flask.request.form.get('ver', '1') + '&second=' + doc_ver + '">(r' + doc_ver + ')</a>' + \
                 ''
 
             warring_edit += '<hr class="main_hr">'
-        else:
-            warring_edit = ''
+            editor_top_text = warring_edit + editor_top_text
 
-        get_name = ''
-        if not section and not flask.request.args.get('plus', None):
-            get_name += '' + \
-                '<a href="/manager/15?plus=' + url_pas(name) + '">(' + load_lang('load') + ')</a> ' + \
-            ''
-            
-        get_name += '' + \
+        editor_top_text += '' + \
             '<a href="/edit_filter">(' + load_lang('edit_filter_rule') + ')</a>' + \
             '<hr class="main_hr">' + \
         ''
-            
-        if flask.request.args.get('plus', None):
-            curs.execute(db_change("select data from data where title = ?"), [flask.request.args.get('plus', 'test')])
-            get_data = curs.fetchall()
-            if get_data:
-                data = get_data[0][0]
-
-        save_button = load_lang('save')
-        menu_plus = [
-            ['delete/' + url_pas(name), load_lang('delete')], 
-            ['move/' + url_pas(name), load_lang('move')], 
-            ['upload', load_lang('upload')]
-        ]
-        sub = load_lang('edit')
 
         curs.execute(db_change('select data from other where name = "edit_bottom_text"'))
         sql_d = curs.fetchall()
@@ -194,34 +171,80 @@ def edit_2(conn, name):
 
         curs.execute(db_change('select data from other where name = "edit_help"'))
         sql_d = curs.fetchall()
-        p_text = sql_d[0][0] if sql_d and sql_d[0][0] != '' else load_lang('default_edit_help')
+        p_text = html.escape(sql_d[0][0]) if sql_d and sql_d[0][0] != '' else load_lang('default_edit_help')
 
         data = re.sub(r'\n+$', '', data)
-        data_old = re.sub(r'\n+$', '', data_old)
+
+        if flask.request.cookies.get('main_css_monaco', '0') == '1':
+            editor_display = 'style="display: none;"'
+            monaco_display = ''
+            add_get_file = '''
+                <link   rel="stylesheet"
+                        data-name="vs/editor/editor.main" 
+                        href="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.20.0/min/vs/editor/editor.main.min.css">
+                <script src="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.20.0/min/vs/loader.min.js"></script>
+            '''
+            
+            if flask.request.cookies.get('main_css_darkmode', '0') == '1':
+                monaco_thema = 'vs-dark'
+            else:
+                monaco_thema = ''
+            
+            add_script = '''
+                require.config({ paths: { 'vs': 'https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.20.0/min/vs' }});
+                require(["vs/editor/editor.main"], function () {
+                    window.editor = monaco.editor.create(document.getElementById('monaco_editor'), {
+                        value: document.getElementById('content').value,
+                        language: 'plaintext',
+                        theme: \'''' + monaco_thema + '''\'
+                    });
+                });
+            '''
+        else:
+            editor_display = ''
+            monaco_display = 'style="display: none;"'
+            add_get_file = ''
+            add_script = ''
 
         return easy_minify(flask.render_template(skin_check(), 
-            imp = [name, wiki_set(), custom(), other2(['(' + sub + ')', 0])],
-            data =  get_name + '''
+            imp = [name, wiki_set(), custom(), other2(['(' + load_lang('edit') + ')', 0])],
+            data =  editor_top_text + add_get_file + '''
                 <form method="post">
                     <script>
                         do_paste_image();
                         do_not_out();
+                        ''' + add_script + '''
                     </script>
-                    ''' + edit_button() + '''
-                    ''' + warring_edit + '''
-                    <textarea id="content" class="content" placeholder="''' + p_text + '''" name="content">''' + html.escape(data) + '''</textarea>
-                    <textarea id="origin" name="o_content">''' + html.escape(data_old) + '''</textarea>
+                    <div ''' + editor_display + '''>''' + edit_button() + '''</div>
+                    <div    id="monaco_editor"
+                            class="content" 
+                            ''' + monaco_display + '''></div>
+                    <textarea   id="content"
+                                ''' + editor_display + '''
+                                class="content" 
+                                placeholder="''' + p_text + '''" 
+                                name="content">''' + html.escape(data) + '''</textarea>
                     <hr class="main_hr">
                     <input placeholder="''' + load_lang('why') + '''" name="send" type="text">
-                    <input id="origin" name="ver" value="''' + (old[0][1] if old else '0') + '''">
+                    <textarea style="display: none;" id="origin">''' + html.escape(data) + '''</textarea>
+                    <input style="display: none;" name="ver" value="''' + doc_ver + '''">
                     <hr class="main_hr">
                     ''' + captcha_get() + ip_warring() + cccb_text + '''
-                    <button id="save" type="submit" onclick="save_stop_exit();">''' + save_button + '''</button>
-                    <button id="preview" type="button" onclick="load_preview(\'''' + url_pas(name) + '\')">' + load_lang('preview') + '''</button>
+                    <button id="save"
+                            type="submit" 
+                            onclick="monaco_to_content(); save_stop_exit();">''' + load_lang('save') + '''</button>
+                    <button id="preview" 
+                            type="button" 
+                            onclick="monaco_to_content(); load_preview(\'''' + url_pas(name) + '\');">' + load_lang('preview') + '''</button>
                 </form>
                 ''' + b_text + '''
                 <hr class="main_hr">
                 <div id="see_preview"></div>
             ''',
-            menu = [['w/' + url_pas(name), load_lang('return')]] + menu_plus
+            menu = [
+                ['w/' + url_pas(name), load_lang('return')],
+                ['delete/' + url_pas(name), load_lang('delete')], 
+                ['move/' + url_pas(name), load_lang('move')], 
+                ['upload', load_lang('upload')]
+            ]
         ))

+ 11 - 10
route/edit_delete.py

@@ -7,6 +7,10 @@ def edit_delete_2(conn, name, app_var):
     if acl_check(name) == 1:
         return re_error('/ban')
 
+    curs.execute(db_change("select title from data where title = ?"), [name])
+    if not curs.fetchall():
+        return redirect('/w/' + url_pas(name))
+
     if flask.request.method == 'POST':
         if captcha_post(flask.request.form.get('g-recaptcha-response', flask.request.form.get('g-recaptcha', ''))) == 1:
             return re_error('/error/13')
@@ -29,7 +33,8 @@ def edit_delete_2(conn, name, app_var):
                 ip,
                 flask.request.form.get('send', ''),
                 leng,
-                'delete'
+                t_check = 'delete',
+                mode = 'delete'
             )
 
             curs.execute(db_change("select title, link from back where title = ? and not type = 'cat' and not type = 'no'"), [name])
@@ -49,26 +54,22 @@ def edit_delete_2(conn, name, app_var):
             )
             if os.path.exists(file_directory):
                 os.remove(file_directory)
-
-        curs.execute(db_change('select data from other where name = "count_all_title"'))
-        curs.execute(db_change("update other set data = ? where name = 'count_all_title'"), [str(int(curs.fetchall()[0][0]) - 1)])
+        else:
+            curs.execute(db_change('select data from other where name = "count_all_title"'))
+            curs.execute(db_change("update other set data = ? where name = 'count_all_title'"), [str(int(curs.fetchall()[0][0]) - 1)])
 
         return redirect('/w/' + url_pas(name))
     else:
-        curs.execute(db_change("select title from data where title = ?"), [name])
-        if not curs.fetchall():
-            return redirect('/w/' + url_pas(name))
-
         return easy_minify(flask.render_template(skin_check(),
             imp = [name, wiki_set(), custom(), other2(['(' + load_lang('delete') + ')', 0])],
             data = '''
                 <form method="post">
                     ''' + ip_warring() + '''
                     <input placeholder="''' + load_lang('why') + '''" name="send" type="text">
-                    <hr class=\"main_hr\">
+                    <hr class="main_hr">
                     ''' + captcha_get() + '''
                     <button type="submit">''' + load_lang('delete') + '''</button>
                 </form>
             ''',
             menu = [['w/' + url_pas(name), load_lang('return')]]
-        ))     
+        ))

+ 1 - 1
route/edit_many_delete.py

@@ -13,7 +13,7 @@ def edit_many_delete_2(conn, app_var):
         for name in all_title:
             edit_delete.edit_delete_2(conn, name, app_var)
 
-            return redirect('/recent_changes')
+        return redirect('/recent_changes')
     else:
         return easy_minify(flask.render_template(skin_check(),
             imp = [load_lang('many_delete'), wiki_set(), custom(), other2([0, 0])],

+ 6 - 3
route/edit_move.py

@@ -45,7 +45,8 @@ def edit_move_2(conn, name):
                     ip_check(),
                     flask.request.form.get('send', ''),
                     '0',
-                    'merge <a>' + name + '</a> - <a>' + move_title + '</a> move'
+                    t_check = 'merge <a>' + name + '</a> - <a>' + move_title + '</a> move',
+                    mode = 'move'
                 )
 
                 curs.execute(db_change("update back set type = 'no' where title = ? and not type = 'cat' and not type = 'no'"), [name])
@@ -112,7 +113,8 @@ def edit_move_2(conn, name):
                         ip_check(),
                         flask.request.form.get('send', ''),
                         '0',
-                        '<a>' + (title_name[0] if title_name[0] != 'test ' + str(i) else name) + '</a> - <a>' + title_name[1] + '</a> move'
+                        t_check = '<a>' + (title_name[0] if title_name[0] != 'test ' + str(i) else name) + '</a> - <a>' + title_name[1] + '</a> move',
+                        mode = 'move'
                     )
 
                     curs.execute(db_change("update history set title = ? where title = ?"), [title_name[1], title_name[0]])
@@ -140,7 +142,8 @@ def edit_move_2(conn, name):
                 ip_check(),
                 flask.request.form.get('send', ''),
                 '0',
-                '<a>' + name + '</a> - <a>' + move_title + '</a> move'
+                t_check = '<a>' + name + '</a> - <a>' + move_title + '</a> move',
+                mode = 'move'
             )
 
             curs.execute(db_change("update back set type = 'no' where title = ? and not type = 'cat' and not type = 'no'"), [name])

+ 2 - 1
route/edit_revert.py

@@ -47,7 +47,8 @@ def edit_revert_2(conn, name):
                 ip_check(),
                 flask.request.form.get('send', ''),
                 leng,
-                'r' + str(num) + ''
+                t_check = 'r' + str(num),
+                mode = 'revert'
             )
 
             render_set(

+ 2 - 5
route/func_title_random.py

@@ -5,11 +5,8 @@ def func_title_random_2(conn):
 
     curs.execute(db_change("" + \
         "select title from data " + \
-        "where title not like 'user:%' and title not like 'category:%' and title not like 'file:%'" + \
+        "where title not like 'user:%' and title not like 'category:%' and title not like 'file:%' " + \
         "order by random() limit 1" + \
     ""))
     data = curs.fetchall()
-    if data:
-        return redirect('/w/' + url_pas(data[0][0]))
-    else:
-        return redirect()
+    return redirect('/w/' + url_pas(data[0][0])) if data else redirect()

+ 15 - 8
route/func_upload.py

@@ -75,23 +75,24 @@ def func_upload_2(conn, app_var):
                 file_d = '' + \
                     '[[file:' + name + ']]\n' + \
                     '{{{[[file:' + name + ']]}}}\n\n' + \
-                    (g_lice + '\n' if g_lice != '' else '') + \
                     flask.request.form.get('f_lice_sel', 'direct_input') + '\n' + \
                     (ip if ip_or_user(ip) != 0 else '[[user:' + ip + ']]') + '\n' + \
                     str(file_size) + ' Byte\n' + \
-                    '[[category:' + re.sub(r'\]', '_', flask.request.form.get('f_lice_sel', '')) + ']]' + \
+                    '[[category:' + re.sub(r'\]', '_', flask.request.form.get('f_lice_sel', '')) + ']]\n' + \
+                    (g_lice if g_lice != '' else '') + \
                 ''
             else:
                 file_d = '' + \
+                    'file:' + name + '\n' + \
                     '/image/' + e_data + '\n\n' + \
-                    (g_lice + '\n' if g_lice != '' else '') + \
                     flask.request.form.get('f_lice_sel', 'direct_input') + '\n' + \
                     ip + \
-                    str(file_size) + ' Byte\n' + \
+                    str(file_size) + ' Byte\n\n' + \
+                    (g_lice if g_lice != '' else '') + \
                 ''
 
             curs.execute(db_change("insert into data (title, data) values (?, ?)"), ['file:' + name, file_d])
-            curs.execute(db_change("insert into acl (title, decu, dis, why, view) values (?, 'admin', '', '', '')"), ['file:' + name])
+            curs.execute(db_change("insert into acl (title, data, type) values (?, 'admin', 'decu')"), ['file:' + name])
 
             render_set(
                 title = 'file:' + name,
@@ -106,7 +107,8 @@ def func_upload_2(conn, app_var):
                 ip,
                 ip,
                 '0',
-                'upload'
+                t_check = 'upload',
+                mode = 'upload'
             )
 
             if file_num:
@@ -117,6 +119,7 @@ def func_upload_2(conn, app_var):
         return redirect('/w/file:' + name)
     else:
         license_list = '<option value="direct_input">' + load_lang('direct_input') + '</option>'
+        file_name = flask.request.args.get('name', '')
 
         curs.execute(db_change("select html from html_filter where kind = 'image_license'"))
         db_data = curs.fetchall()
@@ -126,6 +129,10 @@ def func_upload_2(conn, app_var):
         db_data = curs.fetchall()
         upload_help = ('<hr class="main_hr">' + db_data[0][0]) if db_data and db_data[0][0] != '' else ''
 
+        curs.execute(db_change("select data from other where name = 'upload_default'"))
+        db_data = curs.fetchall()
+        upload_default = html.escape(db_data[0][0]) if db_data and db_data[0][0] != '' else ''
+
         return easy_minify(flask.render_template(skin_check(),
             imp = [load_lang('upload'), wiki_set(), custom(), other2([0, 0])],
             data = '''
@@ -137,13 +144,13 @@ def func_upload_2(conn, app_var):
                 <form method="post" enctype="multipart/form-data" accept-charset="utf8">
                     <input multiple="multiple" type="file" name="f_data[]">
                     <hr class="main_hr">
-                    <input placeholder="''' + load_lang('file_name') + '''" name="f_name" value="''' + flask.request.args.get('name', '') + '''">
+                    <input placeholder="''' + load_lang('file_name') + '''" name="f_name" value="''' + file_name + '''">
                     <hr class="main_hr">
                     <select name="f_lice_sel">
                         ''' + license_list + '''
                     </select>
                     <hr class="main_hr">
-                    <textarea rows="10" placeholder="''' + load_lang('other') + '''" name="f_lice"></textarea>
+                    <textarea rows="10" placeholder="''' + load_lang('other') + '''" name="f_lice">''' + upload_default + '''</textarea>
                     <hr class="main_hr">
                     ''' + captcha_get() + '''
                     <button id="save" type="submit">''' + load_lang('save') + '''</button>

+ 55 - 94
route/give_acl.py

@@ -30,24 +30,18 @@ def give_acl_2(conn, name):
                 check_ok = 'disabled'
 
     if flask.request.method == 'POST':
+        acl_data = [['decu', flask.request.form.get('decu', '')]]
+        acl_data += [['dis', flask.request.form.get('dis', '')]]
+        acl_data += [['view', flask.request.form.get('view', '')]]
+        acl_data += [['why', flask.request.form.get('why', '')]]
+        
         curs.execute(db_change("select title from acl where title = ?"), [name])
         if curs.fetchall():
-            curs.execute(db_change("update acl set decu = ? where title = ?"), [flask.request.form.get('decu', ''), name])
-            curs.execute(db_change("update acl set dis = ? where title = ?"), [flask.request.form.get('dis', ''), name])
-            curs.execute(db_change("update acl set why = ? where title = ?"), [flask.request.form.get('why', ''), name])
-            curs.execute(db_change("update acl set view = ? where title = ?"), [flask.request.form.get('view', ''), name])
+            for i in acl_data:
+                curs.execute(db_change("update acl set data = ? where title = ? and type = ?"), [i[1], name, i[0]])
         else:
-            curs.execute(db_change("insert into acl (title, decu, dis, why, view) values (?, ?, ?, ?, ?)"), [
-                name,
-                flask.request.form.get('decu', ''),
-                flask.request.form.get('dis', ''),
-                flask.request.form.get('why', ''),
-                flask.request.form.get('view', '')
-            ])
-
-        curs.execute(db_change("select title from acl where title = ? and decu = '' and dis = '' and view = ''"), [name])
-        if curs.fetchall():
-            curs.execute(db_change("delete from acl where title = ?"), [name])
+            for i in acl_data:
+                curs.execute(db_change("insert into acl (title, data, type) values (?, ?, ?)"), [name, i[1], i[0]])
 
         all_d = ''
         for i in ['decu', 'dis', 'view']:
@@ -66,93 +60,57 @@ def give_acl_2(conn, name):
 
         return redirect('/acl/' + url_pas(name))
     else:
-        data = '' + \
-            '<h2>' + load_lang('document_acl') + '</h2>' + \
-            '<hr class="main_hr">' + \
-            '<select name="decu" ' + check_ok + '>' + \
-        ''
-
-        if re.search(r'^user:', name):
-            acl_list = get_acl_list('user')
-        else:
-            acl_list = get_acl_list()
-
-        curs.execute(db_change("select decu from acl where title = ?"), [name])
-        acl_data = curs.fetchall()
-        for data_list in acl_list:
-            if acl_data and acl_data[0][0] == data_list:
-                check = 'selected="selected"'
-            else:
-                check = ''
-
-            data += '<option value="' + data_list + '" ' + check + '>' + (data_list if data_list != '' else 'normal') + '</option>'
-
-        data += '</select>'
-
+        data = ''
+        acl_list = get_acl_list('user') if re.search(r'^user:', name) else get_acl_list()
         if not re.search(r'^user:', name):
+            acl_get_list = [
+                [load_lang('document_acl'), 'decu'], 
+                [load_lang('discussion_acl'), 'dis'], 
+                [load_lang('view_acl'), 'view']
+            ]
+        else:
+            acl_get_list = [load_lang('document_acl'), 'decu']
+            
+        for i in acl_get_list:
             data += '' + \
+                '<h2>' + i[0] + '</h2>' + \
                 '<hr class="main_hr">' + \
-                '<h2>' + load_lang('discussion_acl') + '</h2>' + \
-                '<hr class="main_hr">' + \
-                '<select name="dis" ' + check_ok + '>' + \
+                '<select name="' + i[1] + '" ' + check_ok + '>' + \
             ''
-
-            curs.execute(db_change("select dis, why, view from acl where title = ?"), [name])
+    
+            curs.execute(db_change("select data from acl where title = ? and type = ?"), [name, i[1]])
             acl_data = curs.fetchall()
             for data_list in acl_list:
-                if acl_data and acl_data[0][0] == data_list:
-                    check = 'selected="selected"'
-                else:
-                    check = ''
-
+                check = 'selected="selected"' if acl_data and acl_data[0][0] == data_list else ''
                 data += '<option value="' + data_list + '" ' + check + '>' + (data_list if data_list != '' else 'normal') + '</option>'
-
+    
             data += '</select>'
+            data += '<hr class="main_hr">'
 
-            data += '' + \
-                '<hr class="main_hr">' + \
-                '<h2>' + load_lang('view_acl') + '</h2>' + \
-                '<hr class="main_hr">' + \
-                '<select name="view" ' + check_ok + '>' + \
-            ''
-            for data_list in acl_list:
-                if acl_data and acl_data[0][2] == data_list:
-                    check = 'selected="selected"'
-                else:
-                    check = ''
-
-                data += '<option value="' + data_list + '" ' + check + '>' + (data_list if data_list != '' else 'normal') + '</option>'
-
-            data += '''
-                </select>
-                <hr class="main_hr">
-                <h2 id="exp">''' + load_lang('explanation') + '''</h2>
-                <ul>
-                    <li>normal : ''' + load_lang('unset') + '''</li>
-                    <li>admin : ''' + load_lang('admin_acl') + '''</li>
-                    <li>user : ''' + load_lang('member_acl') + '''</li>
-                    <li>50_edit : ''' + load_lang('50_edit_acl') + '''</li>
-                    <li>all : ''' + load_lang('all_acl') + '''</li>
-                    <li>email : ''' + load_lang('email_acl') + '''</li>
-                    <li>owner : ''' + load_lang('owner_acl') + '''</li>
-                    <li>ban : ''' + load_lang('ban_acl') + '''</li>
-                    <li>before : ''' + load_lang('before_acl') + '''</li>
-                    <li>30_day : ''' + load_lang('30_day_acl') + '''</li>
-                    <li>ban_admin : ''' + load_lang('ban_admin_acl') + '''</li>
-                </ul>
-            '''
+        curs.execute(db_change("select data from acl where title = ? and type = ?"), [name, 'why'])
+        acl_data = curs.fetchall()
+        acl_why = html.escape(acl_data[0][0]) if acl_data else ''
+        data += '' + \
+            '<hr class="main_hr">' + \
+            '<input value="' + acl_why + '" placeholder="' + load_lang('why') + '" name="why" type="text" ' + check_ok + '>' + \
+        ''
 
-            if acl_data:
-                data += '' + \
-                    '<hr class="main_hr">' + \
-                    '<input value="' + html.escape(acl_data[0][1]) + '" placeholder="' + load_lang('why') + '" name="why" type="text" ' + check_ok + '>' + \
-                ''
-            else:
-                data += '' + \
-                    '<hr class="main_hr">' + \
-                    '<input placeholder="' + load_lang('why') + '" name="why" type="text" ' + check_ok + '>' + \
-                ''
-                
+        data += '''
+            <h2 id="exp">''' + load_lang('explanation') + '''</h2>
+            <ul class="inside_ul">
+                <li>normal : ''' + load_lang('unset') + '''</li>
+                <li>admin : ''' + load_lang('admin_acl') + '''</li>
+                <li>user : ''' + load_lang('member_acl') + '''</li>
+                <li>50_edit : ''' + load_lang('50_edit_acl') + '''</li>
+                <li>all : ''' + load_lang('all_acl') + '''</li>
+                <li>email : ''' + load_lang('email_acl') + '''</li>
+                <li>owner : ''' + load_lang('owner_acl') + '''</li>
+                <li>ban : ''' + load_lang('ban_acl') + '''</li>
+                <li>before : ''' + load_lang('before_acl') + '''</li>
+                <li>30_day : ''' + load_lang('30_day_acl') + '''</li>
+                <li>ban_admin : ''' + load_lang('ban_admin_acl') + '''</li>
+            </ul>
+        '''
 
         return easy_minify(flask.render_template(skin_check(),
             imp = [name, wiki_set(), custom(), other2(['(' + load_lang('acl') + ')', 0])],
@@ -160,9 +118,12 @@ def give_acl_2(conn, name):
                 <form method="post">
                     <a href="/setting/8">(''' + load_lang('main_acl_setting') + ''')</a>
                     ''' + data + '''
-                    <hr class="main_hr">
                     <button type="submit" ''' + check_ok + '''>''' + load_lang('save') + '''</button>
                 </form>
             ''',
-            menu = [['w/' + url_pas(name), load_lang('document')], ['manager', load_lang('admin')], ['admin_log?search=' + url_pas('acl (' + name + ')'), load_lang('acl_record')]]
+            menu = [
+                ['w/' + url_pas(name), load_lang('document')], 
+                ['manager', load_lang('admin')], 
+                ['admin_log?search=' + url_pas('acl (' + name + ')'), load_lang('acl_record')]
+            ]
         ))

+ 22 - 51
route/give_admin_groups.py

@@ -3,79 +3,50 @@ from .tool.func import *
 def give_admin_groups_2(conn, name):
     curs = conn.cursor()
 
+    acl_name_list = ['ban', 'nothing', 'toron', 'check', 'acl', 'hidel', 'give', 'owner']
+    
     if flask.request.method == 'POST':
         if admin_check(None, 'admin_plus (' + name + ')') != 1:
             return re_error('/error/3')
 
         curs.execute(db_change("delete from alist where name = ?"), [name])
-
-        if flask.request.form.get('ban', 0) != 0:
-            curs.execute(db_change("insert into alist (name, acl) values (?, 'ban')"), [name])
-
-        if flask.request.form.get('toron', 0) != 0:
-            curs.execute(db_change("insert into alist (name, acl) values (?, 'toron')"), [name])
-
-        if flask.request.form.get('check', 0) != 0:
-            curs.execute(db_change("insert into alist (name, acl) values (?, 'check')"), [name])
-
-        if flask.request.form.get('acl', 0) != 0:
-            curs.execute(db_change("insert into alist (name, acl) values (?, 'acl')"), [name])
-
-        if flask.request.form.get('hidel', 0) != 0:
-            curs.execute(db_change("insert into alist (name, acl) values (?, 'hidel')"), [name])
-
-        if flask.request.form.get('give', 0) != 0:
-            curs.execute(db_change("insert into alist (name, acl) values (?, 'give')"), [name])
-
-        if flask.request.form.get('owner', 0) != 0:
-            curs.execute(db_change("insert into alist (name, acl) values (?, 'owner')"), [name])
+        for i in acl_name_list:
+            if flask.request.form.get(i, 0) != 0:
+                curs.execute(db_change("insert into alist (name, acl) values (?, ?)"), [name, i])
 
         conn.commit()
 
         return redirect('/admin_plus/' + url_pas(name))
     else:
-        data = '<ul>'
-
+        data = ''
         exist_list = ['', '', '', '', '', '', '', '']
+        state = 'disabled' if admin_check() != 1 else ''
 
         curs.execute(db_change('select acl from alist where name = ?'), [name])
         acl_list = curs.fetchall()
         for go in acl_list:
-            if go[0] == 'ban':
-                exist_list[0] = 'checked="checked"'
-            elif go[0] == 'toron':
-                exist_list[2] = 'checked="checked"'
-            elif go[0] == 'check':
-                exist_list[3] = 'checked="checked"'
-            elif go[0] == 'acl':
-                exist_list[4] = 'checked="checked"'
-            elif go[0] == 'hidel':
-                exist_list[5] = 'checked="checked"'
-            elif go[0] == 'give':
-                exist_list[6] = 'checked="checked"'
-            elif go[0] == 'owner':
-                exist_list[7] = 'checked="checked"'
-
-        if admin_check() != 1:
-            state = 'disabled'
-        else:
-            state = ''
-
-        acl_name_list = ['ban', 'nothing', 'toron', 'check', 'acl', 'hidel', 'give', 'owner']
+            exist_list[acl_name_list.index(go[0])] = 'checked="checked"'
+            
         for i in range(0, 8):
             if i != 1:
-                data += '<li><input type="checkbox" ''' + state +  ' name="' + acl_name_list[i] + '" ' + exist_list[i] + '> ' + acl_name_list[i] + '</li>'
+                data += '' + \
+                    '<input type="checkbox" ' + \
+                            state + ' ' + \
+                            'name="' + acl_name_list[i] + '" ' + \
+                            exist_list[i] + '> ' + acl_name_list[i] + \
+                    '<hr class="main_hr">' + \
+                ''
 
-        data += '</ul>'
+        data += ''
 
         return easy_minify(flask.render_template(skin_check(),
             imp = [name, wiki_set(), custom(), other2(['(' + load_lang('admin_group') + ')', 0])],
-            data =  '''
+            data = '''
                 <form method="post">
                     ''' + data + '''
-                    <hr class=\"main_hr\">
+                    <hr class="main_hr">
                     <h2>''' + load_lang('explanation') + '''</h2>
-                    <ul>
+                    <ul class="inside_ul">
                         <li>ban : ''' + load_lang('ban_authority') + '''</li>
                         <li>toron : ''' + load_lang('discussion_authority') + '''</li>
                         <li>check : ''' + load_lang('user_check_authority') + '''</li>
@@ -84,9 +55,9 @@ def give_admin_groups_2(conn, name):
                         <li>give : ''' + load_lang('authorization_authority') + '''</li>
                         <li>owner : ''' + load_lang('owner_authority') + '''</li>
                     </ul>
-                    <hr class=\"main_hr\">
+                    <hr class="main_hr">
                     <button ''' + state +  ''' type="submit">''' + load_lang('save') + '''</button>
                 </form>
             ''',
             menu = [['give_log', load_lang('return')]]
-        ))     
+        ))

+ 14 - 10
route/give_delete_admin_group.py

@@ -8,16 +8,20 @@ def delete_admin_group_2(conn, name):
     
     if flask.request.method == 'POST':
         admin_check(None, 'alist del ' + name)
+
         curs.execute(db_change("delete from alist where name = ?"), [name])
+        curs.execute(db_change("update user set acl = 'user' where acl = ?"), [name])
+
+        conn.commit()
 
         return redirect('/give_log')
-    
-    return easy_minify(flask.render_template(skin_check(),
-        imp = [load_lang("delete_admin_group"), wiki_set(), custom(), other2(['(' + name + ')', 0])],
-        data = '''
-            <form method=post>
-                <button type=submit>''' + load_lang('start') + '''</button>
-            </form>
-        ''',
-        menu = [['give_log', load_lang('return')]]
-    ))  
+    else:
+        return easy_minify(flask.render_template(skin_check(),
+            imp = [load_lang("delete_admin_group"), wiki_set(), custom(), other2(['(' + name + ')', 0])],
+            data = '''
+                <form method=post>
+                    <button type=submit>''' + load_lang('start') + '''</button>
+                </form>
+            ''',
+            menu = [['give_log', load_lang('return')]]
+        ))  

+ 6 - 20
route/give_history_add.py

@@ -21,6 +21,7 @@ def give_history_add_2(conn, name):
             'Add:' + flask.request.form.get('get_ip', ''),
             flask.request.form.get('send', ''),
             leng,
+            t_check = 'add',
             mode = 'add'
         )
 
@@ -28,37 +29,22 @@ def give_history_add_2(conn, name):
 
         return redirect('/history/' + url_pas(name))
     else:
-        curs.execute(db_change('select data from other where name = "edit_bottom_text"'))
-        sql_d = curs.fetchall()
-        if sql_d and sql_d[0][0] != '':
-            b_text = '<hr class=\"main_hr\">' + sql_d[0][0]
-        else:
-            b_text = ''
-
-        curs.execute(db_change('select data from other where name = "edit_help"'))
-        sql_d = curs.fetchall()
-        if sql_d and sql_d[0][0] != '':
-            p_text = sql_d[0][0]
-        else:
-            p_text = load_lang('default_edit_help')
-
         return easy_minify(flask.render_template(skin_check(),
             imp = [load_lang('history_add'), wiki_set(), custom(), other2(['(' + name + ')', 0])],
             data = '''
                 <form method="post">
                     <script>do_stop_exit();</script>
                     ''' + edit_button() + '''
-                    <textarea rows="25" id="content" placeholder="''' + p_text + '''" name="content"></textarea>
-                    <hr class=\"main_hr\">
+                    <textarea rows="25" id="content" name="content"></textarea>
+                    <hr class="main_hr">
                     <input placeholder="''' + load_lang('why') + '''" name="send" type="text">
-                    <hr class=\"main_hr\">
+                    <hr class="main_hr">
                     <input placeholder="''' + load_lang('name') + '''" name="get_ip" type="text">
-                    <hr class=\"main_hr\">
+                    <hr class="main_hr">
                     <button id="save" type="submit" onclick="go_save_zone = 1;">''' + load_lang('save') + '''</button>
                     <button id="preview" type="button" onclick="load_preview(\'''' + url_pas(name) + '\')">' + load_lang('preview') + '''</button>
                 </form>
-                ''' + b_text + '''
-                <hr class=\"main_hr\">
+                <hr class="main_hr">
                 <div id="see_preview"></div>
             ''',
             menu = [['history/' + url_pas(name), load_lang('return')]]

+ 17 - 22
route/give_user_ban.py

@@ -4,19 +4,13 @@ def give_user_ban_2(conn, name):
     curs = conn.cursor()
 
     band = flask.request.args.get('type', '')
-    if band == '':
-        if name and ip_or_user(name) == 0:
-            curs.execute(db_change("select acl from user where id = ?"), [name])
-            user = curs.fetchall()
-            if not user:
-                return re_error('/error/2')
-
-            if user and user[0][0] != 'user':
-                if admin_check() != 1:
-                    return re_error('/error/4')
-
-    if ban_check(ip = ip_check(), tool = 'login') == 1:
-        return re_error('/ban')
+    ip = ip_check()
+    if ban_check(ip = ip, tool = 'login') == 1:
+    	if ip_or_user(ip) == 1 or admin_check('all', None, ip) == 0:
+            return re_error('/ban')
+    else:
+    	if admin_check(1, None, ip) !=1:
+    	    return re_error('/error/3')
 
     if flask.request.method == 'POST':
         end = flask.request.form.get('second', '0')
@@ -40,8 +34,12 @@ def give_user_ban_2(conn, name):
             if admin_check(None, 'ban' + (' ' + type_d if type_d else '') + ' (' + name + ')') != 1:
                 return re_error('/error/3')
         else:
-            if admin_check(1, 'ban (' + name + ')') != 1:
-                return re_error('/error/3')
+            if name == ip:
+                if admin_check('all', 'ban (' + name + ')') != 1:
+                    return re_error('/error/3')
+            else:
+            	if admin_check(1, 'ban (' + name + ')') != 1:
+                    return re_error('/error/3')
 
         ban_insert(
             name,
@@ -54,9 +52,6 @@ def give_user_ban_2(conn, name):
 
         return redirect('/block_log')
     else:
-        if admin_check(1) != 1:
-            return re_error('/error/3')
-
         curs.execute(db_change("select end, why from rb where block = ? and ongoing = '1' and band = ?"), [name, band])
         end = curs.fetchall()
         if end:
@@ -66,9 +61,9 @@ def give_user_ban_2(conn, name):
             action = 'action="/ban/' + url_pas(name) + ('?type=' + band if band != '' else '') + '"'
 
             if end[0][0] == '':
-                data = '<ul><li>' + load_lang('limitless') + '</li>'
+                data = '<ul class="inside_ul"><li>' + load_lang('limitless') + '</li>'
             else:
-                data = '<ul><li>' + load_lang('period') + ' : ' + end[0][0] + '</li>'
+                data = '<ul class="inside_ul"><li>' + load_lang('period') + ' : ' + end[0][0] + '</li>'
 
             curs.execute(db_change("select block from rb where block = ? and login = 'O' and ongoing = '1'"), [name])
             if curs.fetchall():
@@ -89,10 +84,10 @@ def give_user_ban_2(conn, name):
             
             time_data = [
                 ['86400', load_lang('1_day')],
-                ['432000', load_lang('5_day')],
+                ['432000', load_lang('5_day')],
                 ['2592000', load_lang('30_day')],
                 ['15552000', load_lang('180_day')],
-                ['31104000', load_lang('360_day')],
+                ['31104000', load_lang('360_day')],
                 ['0', load_lang('limitless')]
             ]
             insert_data = ''

+ 12 - 5
route/give_user_check.py

@@ -117,7 +117,16 @@ def give_user_check_2(conn, name):
 
                 div += '''
                     <tr>
-                        <td><a href="/check/''' + url_pas(data[0]) + '''">''' + data[0] + '''</a></td>
+                        <td>
+                            <a href="/check/''' + url_pas(data[0]) + '''">''' + data[0] + '''</a>
+                            <a  href="/check_delete''' + \
+                                '''?name=''' + url_pas(data[0]) + \
+                                '''&ip=''' + url_pas(data[1]) + \
+                                '''&time=''' + url_pas(data[3].replace(' ', '').replace(':', '').replace('-', '')) + \
+                                '''&return_type=''' + ('0' if ip_or_user(name) == 0 else '1') + '''">
+                                (''' + load_lang('delete') + ''')
+                            </a>
+                        </td>
                         <td><a href="/check/''' + url_pas(data[1]) + '''">''' + data[1] + '''</a></td>
                         <td>''' + data[3] + '''</td>
                     </tr>
@@ -130,9 +139,7 @@ def give_user_check_2(conn, name):
                     </tbody>
                 </table>
             '''
-        else:
-            return re_error('/error/2')
-
+            
         div += next_fix(
             '/check/' + url_pas(name) + ('?plus=' + plus_id + '&num=' if plus_id else '?num='), 
             num, 
@@ -157,7 +164,7 @@ def give_user_check_2(conn, name):
             div += '<li><a href="/check/' + url_pas(i[0]) + '?type=simple">' + i[0] + '</a></li>'
 
         if div != '':
-            div = '<ul>' + div + '</ul>'
+            div = '<ul class="inside_ul">' + div + '</ul>'
             div += next_fix(
                 '/check/' + url_pas(name) + '?type=' + check_type + '&num=', 
                 num, 

+ 46 - 0
route/give_user_check_delete.py

@@ -0,0 +1,46 @@
+from .tool.func import *
+
+def give_user_check_delete_2(conn):
+    curs = conn.cursor()
+    
+    if admin_check() != 1:
+        return re_error('/error/4')
+
+    user_id = flask.request.args.get('name', None)
+    user_ip = flask.request.args.get('ip', None)
+    
+    time = flask.request.args.get('time', None)
+    time_set = re.search(r'([0-9]{4})([0-9]{2})([0-9]{2})([0-9]{2})([0-9]{2})([0-9]{2})', time)
+    if not time_set:
+        return redirect()
+    
+    time_set = time_set.groups()
+    time = time_set[0] + '-' + time_set[1] + '-' + time_set[2] + ' '
+    time += time_set[3] + ':' + time_set[4] + ':' + time_set[5]
+    
+    return_type = flask.request.args.get('return_type', '1')
+        
+    if user_id and user_ip and time:
+        if flask.request.method == 'POST':
+            curs.execute(db_change("delete from ua_d where name = ? and ip = ? and today = ?"), [user_id, user_ip, time])
+            conn.commit()
+            
+            return redirect('/check/' + url_pas(user_id if return_type == '0' else user_ip))
+        else:
+            return easy_minify(flask.render_template(skin_check(),
+                imp = [load_lang('check'), wiki_set(), custom(), other2(['(' + load_lang('delete') + ')', 0])],
+                data = '''
+                    ''' + load_lang('name') + ''' : ''' + user_id + '''
+                    <hr class="main_hr">
+                    ''' + load_lang('ip') + ''' : ''' + user_ip + '''
+                    <hr class="main_hr">
+                    ''' + load_lang('time') + ''' : ''' + time + '''
+                    <hr class="main_hr">
+                    <form method="post">
+                        <button type="submit">''' + load_lang('delete') + '''</button>
+                    </form>
+                ''',
+                menu = [['check/' + url_pas(user_id if return_type == '0' else user_ip), load_lang('return')]]
+            ))
+    else:
+        return redirect()

+ 1 - 1
route/inter_wiki.py

@@ -72,7 +72,7 @@ def inter_wiki_2(conn, tools):
 
     db_data = curs.fetchall()
     if db_data:
-        div += '<ul>'
+        div += '<ul class="inside_ul">'
 
         for data in db_data:
             if tools == 'inter_wiki':

+ 11 - 12
route/list_acl.py

@@ -3,33 +3,32 @@ from .tool.func import *
 def list_acl_2(conn):
     curs = conn.cursor()
 
-    div = '<ul>'
+    num = int(number_check(flask.request.args.get('num', '1')))
+    sql_num = (num * 50 - 50) if num * 50 > 0 else 0
+    div = '<ul class="inside_ul">'
 
-    curs.execute(db_change("select title, why from acl where decu != '' or dis != '' or view != '' order by title desc"))
+    curs.execute(db_change("select distinct title from acl where data != '' order by title desc limit ?, 50"), [sql_num])
     list_data = curs.fetchall()
     for data in list_data:
         if not re.search(r'^user:', data[0]) and not re.search(r'^file:', data[0]):
             curs.execute(db_change("select time from re_admin where what like ? order by time desc limit 1"), ['acl (' + data[0] + ')%'])
             time_data = curs.fetchall()
-            if time_data:
-                time_data = time_data[0][0] + ' | '
-            else:
-                time_data = ''
-                
-            if data[1] != '':
-                why = ' | ' + data[1]
-            else:
-                why = ''
+            time_data = (time_data[0][0] + ' | ') if time_data else ''
+            
+            curs.execute(db_change("select data from acl where title = ? and type = 'why'"), [data[0]])
+            why_data = curs.fetchall()
+            why_data = (' | ' + why_data[0][0]) if why_data and why_data[0][0] != '' else ''
 
             div += '' + \
                 '<li>' + \
                     time_data + \
                     '<a href="/acl/' + url_pas(data[0]) + '">' + data[0] + '</a>' + \
-                     why + \
+                    why_data + \
                 '</li>' + \
             ''
 
     div += '</ul>'
+    div += next_fix('/acl_list?num=', num, list_data)
 
     return easy_minify(flask.render_template(skin_check(),
         imp = [load_lang('acl_document_list'), wiki_set(), custom(), other2([0, 0])],

+ 1 - 1
route/list_admin.py

@@ -3,7 +3,7 @@ from .tool.func import *
 def list_admin_2(conn):
     curs = conn.cursor()
 
-    div = '<ul>'
+    div = '<ul class="inside_ul">'
 
     curs.execute(db_change("select id, acl, date from user where not acl = 'user' order by date desc"))
     for data in curs.fetchall():

+ 1 - 1
route/list_admin_use.py

@@ -12,7 +12,7 @@ def list_admin_use_2(conn):
     if flask.request.method == 'POST':
         return redirect('/admin_log?search=' + flask.request.form.get('search', 'normal'))
     else:
-        list_data = '<ul>'
+        list_data = '<ul class="inside_ul">'
 
         if flask.request.args.get('search', 'normal') == 'normal':
             curs.execute(db_change("select who, what, time from re_admin order by time desc limit ?, 50"), [sql_num])

+ 1 - 1
route/list_give.py

@@ -3,7 +3,7 @@ from .tool.func import *
 def list_give_2(conn):
     curs = conn.cursor()
 
-    list_data = '<ul>'
+    list_data = '<ul class="inside_ul">'
     back = ''
 
     curs.execute(db_change("select distinct name from alist order by name asc"))

+ 1 - 1
route/list_image_file.py

@@ -9,7 +9,7 @@ def list_image_file_2(conn):
     else:
         sql_num = 0
 
-    list_data = '<ul>'
+    list_data = '<ul class="inside_ul">'
     back = ''
 
     curs.execute(db_change("select title from data where title like 'file:%' limit ?, 50"), [sql_num])

+ 24 - 0
route/list_long_page.py

@@ -0,0 +1,24 @@
+from .tool.func import *
+
+def list_long_page_2(conn, tool):
+    curs = conn.cursor()
+
+    curs.execute(db_change('select data from other where name = "count_all_title"'))
+    if int(curs.fetchall()[0][0]) > 30000:
+        return re_error('/error/25')
+
+    div = '<ul class="inside_ul">'
+    select_data = 'desc' if tool == 'long_page' else 'asc'
+    title = 'long_page' if tool == 'long_page' else 'short_page'
+
+    curs.execute(db_change("select title, length(data) from data order by length(data) " + select_data + " limit 50"))
+    for data in curs.fetchall():
+        div += '<li>' + str(data[1]) + ' : <a href="/w/' + url_pas(data[0]) + '">' + data[0] + '</a></li>'
+
+    div += '</ul>'
+
+    return easy_minify(flask.render_template(skin_check(),
+        imp = [load_lang(title), wiki_set(), custom(), other2([0, 0])],
+        data = div,
+        menu = [['other', load_lang('return')]]
+    ))

+ 1 - 1
route/list_not_close_topic.py

@@ -3,7 +3,7 @@ from .tool.func import *
 def list_not_close_topic_2(conn):
     curs = conn.cursor()
 
-    div = '<ul>'
+    div = '<ul class="inside_ul">'
 
     curs.execute(db_change('select title, sub, date, code from rd where stop != "O" order by date desc'))
     n_list = curs.fetchall()

+ 1 - 1
route/list_old_page.py

@@ -13,7 +13,7 @@ def list_old_page_2(conn):
     if int(curs.fetchall()[0][0]) > 30000:
         return re_error('/error/25')
 
-    div = '<ul>'
+    div = '<ul class="inside_ul">'
 
     curs.execute(db_change('' + \
         'select title, date from history h ' + \

+ 2 - 5
route/list_please.py

@@ -4,16 +4,13 @@ def list_please_2(conn):
     curs = conn.cursor()
 
     num = int(number_check(flask.request.args.get('num', '1')))
-    if num * 50 > 0:
-        sql_num = num * 50 - 50
-    else:
-        sql_num = 0
+    sql_num = (num * 50 - 50) if num * 50 > 0 else 0
 
     curs.execute(db_change('select data from other where name = "count_all_title"'))
     if int(curs.fetchall()[0][0]) > 30000:
         return re_error('/error/25')
 
-    div = '<ul>'
+    div = '<ul class="inside_ul">'
 
     curs.execute(db_change("select distinct title from back where type = 'no' order by title asc limit ?, 50"), [sql_num])
     data_list = curs.fetchall()

+ 10 - 12
route/list_title_index.py

@@ -5,10 +5,7 @@ def list_title_index_2(conn):
 
     page = int(number_check(flask.request.args.get('page', '1')))
     num = int(number_check(flask.request.args.get('num', '100')))
-    if page * num > 0:
-        sql_num = page * num - num
-    else:
-        sql_num = 0
+    sql_num = (page * num - num) if page * num > 0 else 0
 
     all_list = sql_num + 1
 
@@ -20,7 +17,7 @@ def list_title_index_2(conn):
     curs.execute(db_change("select title from data order by title asc limit ?, ?"), [sql_num, num])
     title_list = curs.fetchall()
     if title_list:
-        data += '<hr class=\"main_hr\"><ul>'
+        data += '<hr class="main_hr"><ul class="inside_ul">'
 
     for list_data in title_list:
         data += '<li>' + str(all_list) + '. <a href="/w/' + url_pas(list_data[0]) + '">' + list_data[0] + '</a></li>'
@@ -30,7 +27,8 @@ def list_title_index_2(conn):
         count_end = []
 
         curs.execute(db_change('select data from other where name = "count_all_title"'))
-        if int(curs.fetchall()[0][0]) < 30000:
+        all_title = curs.fetchall()
+        if int(all_title[0][0]) < 30000:
             curs.execute(db_change("select count(*) from data"))
             count = curs.fetchall()
             if count:
@@ -51,12 +49,12 @@ def list_title_index_2(conn):
 
             data += '''
                 </ul>
-                <hr class=\"main_hr\">
-                <ul>
+                <hr class="main_hr">
+                <ul class="inside_ul">
                     <li>''' + load_lang('all') + ' : ' + str(count_end[0]) + '''</li>
                 </ul>
-                <hr class=\"main_hr\">
-                <ul>
+                <hr class="main_hr">
+                <ul class="inside_ul">
                     <li>''' + load_lang('category') + ' : ' + str(count_end[1]) + '''</li>
                     <li>''' + load_lang('user_document') + ' : ' + str(count_end[2]) + '''</li>
                     <li>''' + load_lang('file') + ' : ' + str(count_end[3]) + '''</li>
@@ -65,8 +63,8 @@ def list_title_index_2(conn):
         else:
             data += '''
                 </ul>
-                <hr class=\"main_hr\">
-                <ul>
+                <hr class="main_hr">
+                <ul class="inside_ul">
                     <li>''' + load_lang('all') + ' : ' + all_title[0][0] + '''</li>
             '''
 

+ 1 - 1
route/list_user.py

@@ -6,7 +6,7 @@ def list_user_2(conn):
     num = int(number_check(flask.request.args.get('num', '1')))
     sql_num = (num * 50 - 50) if num * 50 > 0 else 0
 
-    list_data = '<ul>'
+    list_data = '<ul class="inside_ul">'
 
     curs.execute(db_change("select id, date from user order by date desc limit ?, 50"), [sql_num])
     user_list = curs.fetchall()

+ 4 - 20
route/login.py

@@ -7,7 +7,7 @@ def login_2(conn):
     if ip_or_user(ip) == 0:
         return redirect('/user')
 
-    if ban_check(tool = 'login') == 1:
+    if ban_check(None, 'login') == 1:
         return re_error('/ban')
 
     if flask.request.method == 'POST':
@@ -16,7 +16,7 @@ def login_2(conn):
         else:
             captcha_post('', 0)
 
-        agent = flask.request.headers.get('User-Agent')
+        user_agent = flask.request.headers.get('User-Agent', '')
         user_id = flask.request.form.get('id', '')
 
         curs.execute(db_change("select pw, encode from user where id = ?"), [user_id])
@@ -36,33 +36,17 @@ def login_2(conn):
         curs.execute(db_change('select data from user_set where name = "2fa" and id = ?'), [user_id])
         fa_data = curs.fetchall()
         if fa_data and fa_data[0][0] != '':
-            curs.execute(db_change("select css from custom where user = ?"), [user_id])
-            css_data = curs.fetchall()
-            flask.session['b_head'] = css_data[0][0] if css_data else ''
             flask.session['b_id'] = user_id
 
             return redirect('/2fa_login')
         else:
-            curs.execute(db_change("select css from custom where user = ?"), [user_id])
-            css_data = curs.fetchall()
-            flask.session['head'] = css_data[0][0] if css_data else ''
             flask.session['id'] = user_id
 
-            curs.execute(db_change("insert into ua_d (name, ip, ua, today, sub) values (?, ?, ?, ?, '')"), [
-                user_id, 
-                ip, 
-                agent, 
-                get_time()
-            ])
+            ua_plus(user_id, ip, user_agent, get_time())
             conn.commit()
 
             return redirect('/user')
     else:
-        http_warring = '' + \
-            '<hr class="main_hr">' + \
-            '<span>' + load_lang('http_warring') + '</span>' + \
-        ''
-
         return easy_minify(flask.render_template(skin_check(),
             imp = [load_lang('login'), wiki_set(), custom(), other2([0, 0])],
             data =  '''
@@ -73,7 +57,7 @@ def login_2(conn):
                         <hr class=\"main_hr\">
                         ''' + captcha_get() + '''
                         <button type="submit">''' + load_lang('login') + '''</button>
-                        ''' + http_warring + '''
+                        ''' + http_warring() + '''
                     </form>
                     ''',
             menu = [['user', load_lang('return')]]

+ 4 - 16
route/login_2fa.py

@@ -10,7 +10,7 @@ def login_2fa_2(conn):
     if ip_or_user(ip) == 0:
         return redirect('/user')
 
-    if ban_check(tool = 'login') == 1:
+    if ban_check(None, 'login') == 1:
         return re_error('/ban')
 
     if flask.request.method == 'POST':
@@ -19,7 +19,7 @@ def login_2fa_2(conn):
         else:
             captcha_post('', 0)
 
-        agent = flask.request.headers.get('User-Agent')
+        user_agent = flask.request.headers.get('User-Agent', '')
         user_id = flask.session['b_id']
 
         curs.execute(db_change('select data from user_set where name = "2fa_pw" and id = ?'), [user_id])
@@ -38,27 +38,15 @@ def login_2fa_2(conn):
             if pw_check_d != 1:
                 return re_error('/error/10')
 
-        flask.session['head'] = flask.session['b_head']
         flask.session['id'] = user_id
 
-        curs.execute(db_change("insert into ua_d (name, ip, ua, today, sub) values (?, ?, ?, ?, '')"), [
-            user_id, 
-            ip, 
-            agent, 
-            get_time()
-        ])
+        ua_plus(user_id, ip, user_agent, get_time())
         conn.commit()
 
         flask.session.pop('b_id', None)
-        flask.session.pop('b_head', None)
 
         return redirect('/user')
     else:
-        http_warring = '' + \
-            '<hr class="main_hr">' + \
-            '<span>' + load_lang('http_warring') + '</span>' + \
-        ''
-
         return easy_minify(flask.render_template(skin_check(),
             imp = [load_lang('login'), wiki_set(), custom(), other2([0, 0])],
             data =  '''
@@ -67,7 +55,7 @@ def login_2fa_2(conn):
                         <hr class=\"main_hr\">
                         ''' + captcha_get() + '''
                         <button type="submit">''' + load_lang('login') + '''</button>
-                        ''' + http_warring + '''
+                        ''' + http_warring() + '''
                     </form>
                     ''',
             menu = [['user', load_lang('return')]]

+ 107 - 122
route/login_check_key.py

@@ -3,150 +3,135 @@ from .tool.func import *
 def login_check_key_2(conn, tool):
     curs = conn.cursor()
 
-    # 난잡한 코드 정리 필요
-    if flask.request.method == 'POST':
-        if tool == 'check_pass_key':
-            if 'c_id' in flask.session and flask.session['c_key'] == flask.request.form.get('key', None):
-                hashed = pw_encode(flask.session['c_key'])
-
-                curs.execute(db_change("update user set pw = ? where id = ?"), [hashed, flask.session['c_id']])
-                conn.commit()
-
-                d_id = flask.session['c_id']
-                pw = flask.session['c_key']
-
-                flask.session.pop('c_id', None)
-                flask.session.pop('c_key', None)
-
-                curs.execute(db_change('select data from other where name = "reset_user_text"'))
-                sql_d = curs.fetchall()
-                if sql_d and sql_d[0][0] != '':
-                    b_text = sql_d[0][0] + '<hr class="main_hr">'
-                else:
-                    b_text = ''
-
-                curs.execute(db_change('select data from user_set where name = "2fa" and id = ?'), [d_id])
+    if  flask.request.method == 'POST' or \
+        ('c_key' in flask.session and flask.session['c_key'] == 'email_pass'):
+        re_set_list = ['c_id', 'c_pw', 'c_ans', 'c_que', 'c_key', 'c_type', 'c_email']
+        ip = ip_check()
+        input_key = flask.request.form.get('key', '')
+        user_agent = flask.request.headers.get('User-Agent', '')
+
+        if  'c_type' in flask.session and \
+            flask.session['c_type'] == 'pass_find' and \
+            flask.session['c_key'] == input_key:
+            curs.execute(db_change("update user set pw = ? where id = ?"), [pw_encode(flask.session['c_key']), flask.session['c_id']])
+            conn.commit()
+
+            user_id = flask.session['c_id']
+            user_pw = flask.session['c_key']
+
+            for i in re_set_list:
+                flask.session.pop(i, None)
+
+            curs.execute(db_change('select data from other where name = "reset_user_text"'))
+            sql_d = curs.fetchall()
+            b_text = (sql_d[0][0] + '<hr class="main_hr">') if sql_d and sql_d[0][0] != '' else ''
+
+            curs.execute(db_change('select data from user_set where name = "2fa" and id = ?'), [user_id])
+            if curs.fetchall():
+                curs.execute(db_change("update user_set set data = '' where name = '2fa' and id = ?"), [user_id])
+
+            return easy_minify(flask.render_template(skin_check(),
+                imp = [load_lang('reset_user_ok'), wiki_set(), custom(), other2([0, 0])],
+                data = b_text + load_lang('id') + ' : ' + user_id + '<br>' + load_lang('password') + ' : ' + user_pw,
+                menu = [['user', load_lang('return')]]
+            ))
+        elif    'c_type' in flask.session and \
+                (flask.session['c_key'] == input_key or flask.session['c_key'] == 'email_pass'):
+            curs.execute(db_change('select data from other where name = "encode"'))
+            db_data = curs.fetchall()
+
+            if flask.session['c_type'] == 'register':
+                if flask.session['c_key'] == 'email_pass':
+                    flask.session['c_email'] = ''
+
+                curs.execute(db_change("select id from user limit 1"))
+                first = 1 if not curs.fetchall() else 0
+
+                curs.execute(db_change("select id from user where id = ?"), [flask.session['c_id']])
                 if curs.fetchall():
-                    curs.execute(db_change("update user_set set data = '' where name = '2fa' and id = ?"), [d_id])
+                    for i in re_set_list:
+                        flask.session.pop(i, None)
 
-                return easy_minify(flask.render_template(skin_check(),
-                    imp = [load_lang('reset_user_ok'), wiki_set(), custom(), other2([0, 0])],
-                    data = b_text + load_lang('id') + ' : ' + d_id + '<br>' + load_lang('password') + ' : ' + pw,
-                    menu = [['user', load_lang('return')]]
-                ))
-            else:
-                return redirect('/pass_find')
-        else:
-            ip = ip_check()
-
-            if 'c_id' in flask.session and flask.session['c_key'] == flask.request.form.get('key', None):
-                curs.execute(db_change('select data from other where name = "encode"'))
-                db_data = curs.fetchall()
-
-                if tool == 'check_key':
-                    curs.execute(db_change("select id from user limit 1"))
-                    if not curs.fetchall():
-                        curs.execute(db_change("insert into user (id, pw, acl, date, encode) values (?, ?, 'owner', ?, ?)"), [
-                            flask.session['c_id'],
-                            flask.session['c_pw'],
-                            get_time(),
-                            db_data[0][0]
-                        ])
-
-                        first = 1
-                    else:
-                        curs.execute(db_change('select data from other where name = "requires_approval"'))
-                        requires_approval = curs.fetchall()
-                        if requires_approval and requires_approval[0][0] == 'on':
-                            application_token = ''.join(random.choice("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") for i in range(60))
-                            curs.execute(db_change(
-                                "insert into user_application (id, pw, date, encode, question, answer, token, ip, ua, email) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"
-                            ), [
-                                flask.session['c_id'],
-                                flask.session['c_pw'],
-                                get_time(),
-                                db_data[0][0],
-                                flask.session['c_question'],
-                                flask.session['c_ans'],
-                                application_token,
-                                ip,
-                                flask.request.headers.get('User-Agent'),
-                                flask.session['c_email']
-                            ])
-                            conn.commit()
-
-                            flask.session.pop('c_id', None)
-                            flask.session.pop('c_pw', None)
-                            flask.session.pop('c_key', None)
-                            flask.session.pop('c_email', None)
-                            flask.session.pop('c_question', None)
-                            flask.session.pop('c_ans', None)
-
-                            return redirect('/application_submitted')
-                        else:
-                            curs.execute(db_change("insert into user (id, pw, acl, date, encode) values (?, ?, 'user', ?, ?)"), [
-                                flask.session['c_id'],
-                                flask.session['c_pw'],
-                                get_time(),
-                                db_data[0][0]
-                            ])
-
-                        first = 0
-
-                    agent = flask.request.headers.get('User-Agent')
-
-                    curs.execute(db_change("insert into user_set (name, id, data) values ('email', ?, ?)"), [
+                    return re_error('/error/6')
+            
+                curs.execute(db_change("select id from user_application where id = ?"), [flask.session['c_id']])
+                if curs.fetchall():
+                    for i in re_set_list:
+                        flask.session.pop(i, None)
+
+                    return re_error('/error/6')
+
+                curs.execute(db_change('select data from other where name = "requires_approval"'))
+                requires_approval = curs.fetchall()
+                if requires_approval and requires_approval[0][0] == 'on':
+                    application_token = load_random_key(32)
+                    curs.execute(db_change(
+                        "insert into user_application (id, pw, date, encode, question, answer, token, ip, ua, email) " + \
+                        "values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"
+                    ), [
                         flask.session['c_id'],
+                        flask.session['c_pw'],
+                        get_time(),
+                        db_data[0][0],
+                        flask.session['c_que'],
+                        flask.session['c_ans'],
+                        application_token,
+                        ip,
+                        user_agent,
                         flask.session['c_email']
                     ])
-                    curs.execute(db_change("insert into ua_d (name, ip, ua, today, sub) values (?, ?, ?, ?, '')"), [
+                    conn.commit()
+    
+                    for i in re_set_list:
+                        flask.session.pop(i, None)
+
+                    return redirect('/application_submitted')
+                else:
+                    curs.execute(db_change("insert into user (id, pw, acl, date, encode) values (?, ?, ?, ?, ?)"), [
                         flask.session['c_id'],
-                        ip,
-                        agent,
-                        get_time()
+                        flask.session['c_pw'],
+                        'user' if first == 0 else 'owner',
+                        get_time(),
+                        db_data[0][0]
                     ])
 
-                    flask.session['id'] = flask.session['c_id']
-                    flask.session['head'] = ''
+                curs.execute(db_change("insert into user_set (name, id, data) values ('email', ?, ?)"), [
+                    flask.session['c_id'],
+                    flask.session['c_email']
+                ])
+                ua_plus(flask.session['c_id'], ip, user_agent, get_time())
 
-                    conn.commit()
-                else:
-                    curs.execute(db_change('delete from user_set where name = "email" and id = ?'), [ip])
-                    curs.execute(db_change('insert into user_set (name, id, data) values ("email", ?, ?)'), [ip, flask.session['c_email']])
+                flask.session['id'] = flask.session['c_id']
+                flask.session['head'] = ''
+
+                conn.commit()
+            else:
+                curs.execute(db_change('delete from user_set where name = "email" and id = ?'), [ip])
+                curs.execute(db_change('insert into user_set (name, id, data) values ("email", ?, ?)'), [ip, flask.session['c_email']])
 
-                    first = 0
+                first = 0
 
-                flask.session.pop('c_id', None)
-                flask.session.pop('c_pw', None)
-                flask.session.pop('c_key', None)
-                flask.session.pop('c_email', None)
+            for i in re_set_list:
+                flask.session.pop(i, None)
 
-                if first == 0:
-                    return redirect('/change')
-                else:
-                    return redirect('/setting')
-            else:
-                flask.session.pop('c_id', None)
-                flask.session.pop('c_pw', None)
-                flask.session.pop('c_key', None)
-                flask.session.pop('c_email', None)
+            return redirect('/change') if first == 0 else redirect('/setting') 
+        else:
+            for i in re_set_list:
+                flask.session.pop(i, None)
 
-                return redirect('/user')
+            return redirect('/user')
     else:
         curs.execute(db_change('select data from other where name = "check_key_text"'))
         sql_d = curs.fetchall()
-        if sql_d and sql_d[0][0] != '':
-            b_text = sql_d[0][0] + '<hr class=\"main_hr\">'
-        else:
-            b_text = ''
+        b_text = (sql_d[0][0] + '<hr class="main_hr">') if sql_d and sql_d[0][0] != '' else ''
 
         return easy_minify(flask.render_template(skin_check(),
             imp = [load_lang('check_key'), wiki_set(), custom(), other2([0, 0])],
-            data =  '''
+            data = '''
                 <form method="post">
                     ''' + b_text + '''
                     <input placeholder="''' + load_lang('key') + '''" name="key" type="text">
-                    <hr class=\"main_hr\">
+                    <hr class="main_hr">
                     <button type="submit">''' + load_lang('save') + '''</button>
                 </form>
             ''',

+ 85 - 99
route/login_need_email.py

@@ -2,127 +2,113 @@ from .tool.func import *
 
 def login_need_email_2(conn, tool):
     curs = conn.cursor()
-
+    
     if flask.request.method == 'POST':
-        if tool == 'pass_find':
-            curs.execute(db_change("select id from user_set where id = ? and name = 'email' and data = ?"), [
-                flask.request.form.get('id', ''),
-                flask.request.form.get('email', '')
-            ])
-            if curs.fetchall():
-                flask.session['c_key'] = ''.join(random.choice("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") for i in range(16))
-                flask.session['c_id'] = flask.request.form.get('id', '')
-
-                curs.execute(db_change('select data from other where name = "email_title"'))
-                sql_d = curs.fetchall()
-                if sql_d and sql_d[0][0] != '':
-                    t_text = html.escape(sql_d[0][0])
-                else:
-                    t_text = wiki_set()[0] + ' key'
-
-                curs.execute(db_change('select data from other where name = "email_text"'))
-                sql_d = curs.fetchall()
-                if sql_d and sql_d[0][0] != '':
-                    i_text = html.escape(sql_d[0][0]) + '\n\nKey : ' + flask.session['c_key']
-                else:
-                    i_text = 'Key : ' + flask.session['c_key']
-
-                if send_email(flask.request.form.get('email', ''), t_text, i_text) == 0:
-                    return re_error('/error/18')
-
-                return redirect('/check_pass_key')
+        re_set_list = ['c_id', 'c_pw', 'c_ans', 'c_que', 'c_key', 'c_type']
+    
+        if tool == 'email_change':
+            flask.session['c_key'] = load_random_key(32)
+            flask.session['c_id'] = ip_check()
+            flask.session['c_type'] = 'email_change'
+        elif tool == 'pass_find':
+            user_id = flask.request.form.get('id', '')
+            user_email = flask.request.form.get('email', '')
+
+            flask.session['c_key'] = load_random_key(32)
+            flask.session['c_id'] = user_id
+            flask.session['c_type'] = 'pass_find'
+        else:
+            if not 'c_type' in flask.session:
+                return redirect('/register')
+
+        if tool != 'pass_find':
+            user_email = flask.request.form.get('email', '')
+            email_data = re.search(r'@([^@]+)$', user_email)
+            if email_data:
+                curs.execute(db_change("select html from html_filter where html = ? and kind = 'email'"), [email_data.group(1)])
+                if not curs.fetchall():
+                    for i in re_set_list:
+                        flask.session.pop(i, None)
+                    
+                    return redirect('/email_filter')
             else:
+                for i in re_set_list:
+                    flask.session.pop(i, None)
+                
+                return re_error('/error/36')
+
+        curs.execute(db_change('select data from other where name = "email_title"'))
+        sql_d = curs.fetchall()
+        t_text = html.escape(sql_d[0][0]) if sql_d and sql_d[0][0] != '' else (wiki_set()[0] + ' key')
+
+        curs.execute(db_change('select data from other where name = "email_text"'))
+        sql_d = curs.fetchall()
+        i_text = (html.escape(sql_d[0][0]) + '\n\nKey : ' + flask.session['c_key']) if sql_d and sql_d[0][0] != '' else ('Key : ' + flask.session['c_key'])
+        
+        if tool == 'pass_find':
+            curs.execute(db_change("select id from user_set where id = ? and name = 'email' and data = ?"), [user_id, user_email])
+            if not curs.fetchall():
                 return re_error('/error/12')
-        else:
-            if tool == 'email_change':
-                flask.session['c_key'] = ''.join(random.choice("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") for i in range(16))
-                flask.session['c_id'] = ip_check()
-                flask.session['c_pw'] = ''
-
-            if 'c_id' in flask.session:
-                data = re.search(r'@([^@]+)$', flask.request.form.get('email', ''))
-                if data:
-                    data = data.group(1)
-
-                    curs.execute(db_change("select html from html_filter where html = ? and kind = 'email'"), [data])
-                    if curs.fetchall():
-                        curs.execute(db_change('select id from user_set where name = "email" and data = ?'), [flask.request.form.get('email', '')])
-                        if curs.fetchall():
-                            flask.session.pop('c_id', None)
-                            flask.session.pop('c_pw', None)
-                            flask.session.pop('c_key', None)
+                
+            if send_email(user_email, t_text, i_text) == 0:
+                return re_error('/error/18')
 
-                            # user 대신 오류 화면 보여주게 수정 필요
-                            return redirect('/user')
-                        else:
-                            curs.execute(db_change('select data from other where name = "email_title"'))
-                            sql_d = curs.fetchall()
-                            if sql_d and sql_d[0][0] != '':
-                                t_text = html.escape(sql_d[0][0])
-                            else:
-                                t_text = wiki_set()[0] + ' key'
-
-                            curs.execute(db_change('select data from other where name = "email_text"'))
-                            sql_d = curs.fetchall()
-                            if sql_d and sql_d[0][0] != '':
-                                i_text = html.escape(sql_d[0][0]) + '\n\nKey : ' + flask.session['c_key']
-                            else:
-                                i_text = 'Key : ' + flask.session['c_key']
+            return redirect('/check_key')
+        else:
+            curs.execute(db_change('select id from user_set where name = "email" and data = ?'), [user_email])
+            if curs.fetchall():
+                for i in re_set_list:
+                    flask.session.pop(i, None)
 
-                            if send_email(flask.request.form.get('email', ''), t_text, i_text) == 0:
-                                return re_error('/error/18')
+                return re_error('/error/35')
+            
+            if send_email(user_email, t_text, i_text) == 0:
+                for i in re_set_list:
+                    flask.session.pop(i, None)
 
-                            flask.session['c_email'] = flask.request.form.get('email', '')
+                return re_error('/error/18')
 
-                            if tool == 'email_change':
-                                return redirect('/email_replace')
-                            else:
-                                return redirect('/check_key')
-                    else:
-                        return redirect('/email_filter')
+            flask.session['c_email'] = user_email
 
-            return redirect('/user')
+            return redirect('/check_key')
     else:
         if tool == 'pass_find':
             curs.execute(db_change('select data from other where name = "password_search_text"'))
             sql_d = curs.fetchall()
-            if sql_d and sql_d[0][0] != '':
-                b_text = sql_d[0][0] + '<hr class=\"main_hr\">'
-            else:
-                b_text = ''
+            b_text = (sql_d[0][0] + '<hr class="main_hr">') if sql_d and sql_d[0][0] != '' else ''
 
             return easy_minify(flask.render_template(skin_check(),
                 imp = [load_lang('password_search'), wiki_set(), custom(), other2([0, 0])],
-                data =  b_text + '''
-                        <form method="post">
-                            <input placeholder="''' + load_lang('id') + '''" name="id" type="text">
-                            <hr class=\"main_hr\">
-                            <input placeholder="''' + load_lang('email') + '''" name="email" type="text">
-                            <hr class=\"main_hr\">
-                            <button type="submit">''' + load_lang('save') + '''</button>
-                        </form>
-                        ''',
+                data = b_text + '''
+                    <form method="post">
+                        <input placeholder="''' + load_lang('id') + '''" name="id" type="text">
+                        <hr class="main_hr">
+                        <input placeholder="''' + load_lang('email') + '''" name="email" type="text">
+                        <hr class="main_hr">
+                        <button type="submit">''' + load_lang('save') + '''</button>
+                    </form>
+                ''',
                 menu = [['user', load_lang('return')]]
             ))
         else:
+            if tool == 'need_email' and not 'c_type' in flask.session:
+                return redirect('/register')
+
             curs.execute(db_change('select data from other where name = "email_insert_text"'))
             sql_d = curs.fetchall()
-            if sql_d and sql_d[0][0] != '':
-                b_text = sql_d[0][0] + '<hr class=\"main_hr\">'
-            else:
-                b_text = ''
+            b_text = (sql_d[0][0] + '<hr class="main_hr">') if sql_d and sql_d[0][0] != '' else ''
 
             return easy_minify(flask.render_template(skin_check(),
                 imp = [load_lang('email'), wiki_set(), custom(), other2([0, 0])],
-                data =  '''
-                        <a href="/email_filter">(''' + load_lang('email_filter_list') + ''')</a>
-                        <hr class=\"main_hr\">
-                        ''' + b_text + '''
-                        <form method="post">
-                            <input placeholder="''' + load_lang('email') + '''" name="email" type="text">
-                            <hr class=\"main_hr\">
-                            <button type="submit">''' + load_lang('save') + '''</button>
-                        </form>
-                        ''',
+                data = '''
+                    <a href="/email_filter">(''' + load_lang('email_filter_list') + ''')</a>
+                    <hr class="main_hr">
+                    ''' + b_text + '''
+                    <form method="post">
+                        <input placeholder="''' + load_lang('email') + '''" name="email" type="text">
+                        <hr class="main_hr">
+                        <button type="submit">''' + load_lang('save') + '''</button>
+                    </form>
+                ''',
                 menu = [['user', load_lang('return')]]
             ))

+ 11 - 16
route/login_pw_change.py

@@ -11,8 +11,11 @@ def login_pw_change_2(conn):
         return redirect('/login')
 
     if flask.request.method == 'POST':
-        if flask.request.form.get('pw4', None) and flask.request.form.get('pw2', None):
-            if flask.request.form.get('pw2', None) != flask.request.form.get('pw3', None):
+        now_pw = flask.request.form.get('pw4', None)
+        new_pw = flask.request.form.get('pw2', None)
+        re_pw = flask.request.form.get('pw3', None)
+        if now_pw and new_pw and re_pw:
+            if new_pw != re_pw:
                 return re_error('/error/20')
 
             curs.execute(db_change("select pw, encode from user where id = ?"), [flask.session['id']])
@@ -20,31 +23,23 @@ def login_pw_change_2(conn):
             if not user:
                 return re_error('/error/2')
 
-            pw_check_d = pw_check(
-                flask.request.form.get('pw4', ''),
-                user[0][0],
-                user[0][1],
-                ip
-            )
-            if pw_check_d != 1:
+            if pw_check(now_pw, user[0][0], user[0][1], ip) != 1:
                 return re_error('/error/10')
 
-            hashed = pw_encode(flask.request.form.get('pw2', None))
+            curs.execute(db_change("update user set pw = ? where id = ?"), [pw_encode(new_pw), ip])
 
-            curs.execute(db_change("update user set pw = ? where id = ?"), [hashed, ip])
-
-            return redirect('/user')
+        return redirect('/user')
     else:
         return easy_minify(flask.render_template(skin_check(),
             imp = [load_lang('password_change'), wiki_set(), custom(), other2([0, 0])],
             data = '''
                 <form method="post">
                     <input placeholder="''' + load_lang('now_password') + '''" name="pw4" type="password">
-                    <hr class=\"main_hr\">
+                    <hr class="main_hr">
                     <input placeholder="''' + load_lang('new_password') + '''" name="pw2" type="password">
-                    <hr class=\"main_hr\">
+                    <hr class="main_hr">
                     <input placeholder="''' + load_lang('password_confirm') + '''" name="pw3" type="password">
-                    <hr class=\"main_hr\">
+                    <hr class="main_hr">
                     <button type="submit">''' + load_lang('save') + '''</button>
                 </form>
             ''',

+ 39 - 83
route/login_register.py

@@ -3,7 +3,7 @@ from .tool.func import *
 def login_register_2(conn):
     curs = conn.cursor()
 
-    if ban_check() == 1:
+    if ban_check(None, 'login') == 1:
         return re_error('/ban')
 
     ip = ip_check()
@@ -23,117 +23,73 @@ def login_register_2(conn):
         else:
             captcha_post('', 0)
 
-        if flask.request.form.get('id', None) == '' or flask.request.form.get('pw', None) == '':
+        user_id = flask.request.form.get('id', '')
+        user_pw = flask.request.form.get('pw', '')
+        user_repeat = flask.request.form.get('pw2', '')
+        if user_id == '' or user_pw == '':
             return re_error('/error/27')
 
-        if flask.request.form.get('pw', None) != flask.request.form.get('pw2', None):
+        if user_pw != user_repeat:
             return re_error('/error/20')
 
-        if re.search(r'(?:[^A-Za-zㄱ-힣0-9])', flask.request.form.get('id', None)):
+        if re.search(r'(?:[^A-Za-zㄱ-힣0-9])', user_id):
             return re_error('/error/8')
 
         curs.execute(db_change('select html from html_filter where kind = "name"'))
         set_d = curs.fetchall()
         for i in set_d:
             check_r = re.compile(i[0], re.I)
-            if check_r.search(flask.request.form.get('id', None)):
+            if check_r.search(user_id):
                 return re_error('/error/8')
 
-        if len(flask.request.form.get('id', None)) > 32:
+        if len(user_id) > 32:
             return re_error('/error/7')
 
-        curs.execute(db_change("select id from user where id = ?"), [flask.request.form.get('id', None)])
+        curs.execute(db_change("select id from user where id = ?"), [user_id])
+        if curs.fetchall():
+            return re_error('/error/6')
+    
+        curs.execute(db_change("select id from user_application where id = ?"), [user_id])
         if curs.fetchall():
             return re_error('/error/6')
 
-        hashed = pw_encode(flask.request.form.get('pw', None))
+        hashed = pw_encode(user_pw)
+        ans_q = flask.request.form.get('approval_question_answer', '')
 
         curs.execute(db_change('select data from other where name = "requires_approval"'))
         requires_approval = curs.fetchall()
         requires_approval = requires_approval and requires_approval[0][0] == 'on'
         requires_approval = None if admin == 1 else requires_approval
-
-        approval_question = ''
         if requires_approval:
             curs.execute(db_change('select data from other where name = "approval_question"'))
             approval_question = curs.fetchall()
-            if approval_question and approval_question[0][0]:
-                approval_question = approval_question[0][0]
-            else:
-                approval_question = ''
+            approval_question = approval_question[0][0] if approval_question and approval_question[0][0] else ''
+        else:
+            approval_question = ''
 
+        # c_id, c_pw, c_ans, c_que, c_key, c_type
+        flask.session['c_id'] = user_id
+        flask.session['c_pw'] = hashed
+        flask.session['c_type'] = 'register'
+        if requires_approval:
+            flask.session['c_ans'] = flask.request.form.get('approval_question_answer', '')
+            flask.session['c_que'] = approval_question
+        
         curs.execute(db_change('select data from other where name = "email_have"'))
         sql_data = curs.fetchall()
         if sql_data and sql_data[0][0] != '' and admin != 1:
-            flask.session['c_id'] = flask.request.form.get('id', None)
-            flask.session['c_pw'] = hashed
-            flask.session['c_key'] = ''.join(random.choice("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") for i in range(16))
-            if requires_approval:
-                flask.session['c_ans'] = flask.request.form.get('approval_question_answer')
-                flask.session['c_question'] = approval_question
+            flask.session['c_key'] = load_random_key(32)
 
             return redirect('/need_email')
         else:
-            curs.execute(db_change('select data from other where name = "encode"'))
-            db_data = curs.fetchall()
-
-            curs.execute(db_change("select id from user limit 1"))
-            if not curs.fetchall():
-                curs.execute(db_change("insert into user (id, pw, acl, date, encode) values (?, ?, 'owner', ?, ?)"), [
-                    flask.request.form.get('id', None), 
-                    hashed, 
-                    get_time(), 
-                    db_data[0][0]
-                ])
-
-                first = 1
-            else:
-                if requires_approval:
-                    application_token = ''.join(random.choice("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") for i in range(60))
-                    curs.execute(db_change(
-                        "insert into user_application (id, pw, date, encode, question, answer, token, ip, ua, email) values (?, ?, ?, ?, ?, ?, ?, ?, ?, '')"
-                    ), [
-                        flask.request.form.get('id', None), 
-                        hashed, 
-                        get_time(), 
-                        db_data[0][0], 
-                        approval_question, 
-                        flask.request.form.get('approval_question_answer', None), 
-                        application_token, 
-                        ip_check(), 
-                        flask.request.headers.get('User-Agent')
-                    ])
-                    conn.commit()
-                    
-                    return redirect('/application_submitted')
-                else:
-                    curs.execute(db_change("insert into user (id, pw, acl, date, encode) values (?, ?, 'user', ?, ?)"), [flask.request.form.get('id', None), hashed, get_time(), db_data[0][0]])
-
-                first = 0
-
-            ip = ip_check()
-            agent = flask.request.headers.get('User-Agent')
-
-            curs.execute(db_change("insert into ua_d (name, ip, ua, today, sub) values (?, ?, ?, ?, '')"), [flask.request.form.get('id', None), ip, agent, get_time()])
-
-            flask.session['id'] = flask.request.form.get('id', None)
-            flask.session['head'] = ''
-
-            conn.commit()
-
-            if first == 0:
-                return redirect('/change')
-            else:
-                return redirect('/setting')
-    else:
-        contract = ''
+            flask.session['c_key'] = 'email_pass'
 
+            return redirect('/check_key')
+    else:
         curs.execute(db_change('select data from other where name = "contract"'))
         data = curs.fetchall()
-        if data and data[0][0] != '':
-            contract = data[0][0] + '<hr class=\"main_hr\">'
+        contract = (data[0][0] + '<hr class="main_hr">') if data and data[0][0] != '' else ''
 
-        http_warring = '<hr class=\"main_hr\"><span>' + load_lang('http_warring') + '</span>'
         approval_question = ''
         
         curs.execute(db_change('select data from other where name = "requires_approval"'))
@@ -145,11 +101,11 @@ def login_register_2(conn):
             data = curs.fetchall()
             if data and data[0][0] != '':
                 approval_question = '''
-                    <hr class=\"main_hr\">
+                    <hr class="main_hr">
                     <span>''' + load_lang('approval_question') + ' : ' + data[0][0] + '''<span>
-                    <hr class=\"main_hr\">
+                    <hr class="main_hr">
                     <input placeholder="''' + load_lang('approval_question') + '''" name="approval_question_answer" type="text">
-                    <hr class=\"main_hr\">
+                    <hr class="main_hr">
                 '''
 
         return easy_minify(flask.render_template(skin_check(),
@@ -158,15 +114,15 @@ def login_register_2(conn):
                 <form method="post">
                     ''' + contract + '''
                     <input placeholder="''' + load_lang('id') + '''" name="id" type="text">
-                    <hr class=\"main_hr\">
+                    <hr class="main_hr">
                     <input placeholder="''' + load_lang('password') + '''" name="pw" type="password">
-                    <hr class=\"main_hr\">
+                    <hr class="main_hr">
                     <input placeholder="''' + load_lang('password_confirm') + '''" name="pw2" type="password">
-                    <hr class=\"main_hr\">
+                    <hr class="main_hr">
                     ''' + approval_question + '''
                     ''' + captcha_get() + '''
                     <button type="submit">''' + load_lang('save') + '''</button>
-                    ''' + http_warring + '''
+                    ''' + http_warring() + '''
                 </form>
             ''',
             menu = [['user', load_lang('return')]]

+ 5 - 1
route/main_image_view.py

@@ -6,9 +6,13 @@ def main_image_view_2(conn, name, app_var):
 
     mime_type = re.search(r'([^.]+)$', name)
     if mime_type:
+        mime_type = mime_type.group(1).lower()
+        if mime_type == 'svg':
+            mime_type = 'svg+xml'
+        
         return flask.send_from_directory(
             './' + app_var['path_data_image'], name, 
-            mimetype = 'image/' + mime_type.group(1).lower()
+            mimetype = 'image/' + mime_type
         )
     else:
         return main_error_404.main_error_404_2(conn)

+ 10 - 7
route/main_manager.py

@@ -27,7 +27,7 @@ def main_manager_2(conn, num, r_ver):
             imp = [load_lang('admin_tool'), wiki_set(), custom(), other2([0, 0])],
             data = '''
                 <h2>''' + load_lang('admin') + '''</h2>
-                <ul>
+                <ul class="inside_ul">
                     <li><a href="/manager/2">''' + load_lang('acl_change') + '''</a></li>
                     <li><a href="/manager/3">''' + load_lang('check_user') + '''</a></li>
                     <li><a href="/ban">''' + load_lang('ban') + '''</a></li>
@@ -36,7 +36,7 @@ def main_manager_2(conn, num, r_ver):
                 </ul>
                 <br>
                 <h2>''' + load_lang('owner') + '''</h2>
-                <ul>
+                <ul class="inside_ul">
                     <li><a href="/give_log">''' + load_lang('admin_group_list') + '''</a></li>
                     <li><a href="/many_delete">''' + load_lang('many_delete') + '''</a></li>
                     <li><a href="/applications">''' + load_lang('application_list') + '''</a></li>
@@ -45,7 +45,7 @@ def main_manager_2(conn, num, r_ver):
                     <li><a href="/setting">''' + load_lang('setting') + '''</a></li>
                 </ul>
                 <h3>''' + load_lang('filter') + '''</h3>
-                <ul>
+                <ul class="inside_ul">
                     <li><a href="/edit_filter">''' + load_lang('edit_filter_list') + '''</a></li>
                     <li><a href="/inter_wiki">''' + load_lang('interwiki_list') + '''</a></li>
                     <li><a href="/edit_top">''' + load_lang('edit_tool_list') + '''</a></li>
@@ -57,18 +57,21 @@ def main_manager_2(conn, num, r_ver):
                 </ul>
                 <br>
                 <h2>''' + load_lang('server') + '''</h2>
-                <ul>
+                <ul class="inside_ul">
                     <li><a href="/restart">''' + load_lang('wiki_restart') + '''</a></li>
                     <li><a href="/update">''' + load_lang('update') + '''</a></li>
                 </ul>
                 <br>
                 <h2>''' + load_lang('version') + '''</h2>
-                <ul>
-                    <li><a href="/api/skin_info?all=true">''' + load_lang('skin_info') + '''</a></li>
+                <ul class="inside_ul">
+                    <li>
+                        <a href="/api/skin_info?all=true">''' + load_lang('skin_info') + '''</a>
+                        <span id="need_skin_update"></span>
+                    </li>
                     <li>''' + load_lang('version') + ' : ' + r_ver + '''</li>
                     <li id="ver_send" style="display: none;">''' + load_lang('lastest') + ''' : </li>
                 </ul>
-                <script>load_ver();</script>
+                <script>load_ver(); do_skin_ver_check();</script>
             ''',
             menu = [['other', load_lang('return')]]
         ))

+ 6 - 4
route/main_other.py

@@ -7,13 +7,13 @@ def main_other_2(conn):
         imp = [load_lang('other_tool'), wiki_set(), custom(), other2([0, 0])],
         data = '''
             <h2>''' + load_lang('record') + '''</h2>
-            <ul>
+            <ul class="inside_ul">
                 <li><a href="/manager/6">''' + load_lang('edit_record') + '''</a></li>
                 <li><a href="/manager/7">''' + load_lang('discussion_record') + '''</a></li>
             </ul>
             <br>
             <h2>''' + load_lang('list') + '''</h2>
-            <ul>
+            <ul class="inside_ul">
                 <li><a href="/recent_changes">''' + load_lang('recent_change') + '''</a></li>
                 <li><a href="/recent_discuss">''' + load_lang('recent_discussion') + '''</a></li>
                 <li><a href="/admin_list">''' + load_lang('admin_list') + '''</a></li>
@@ -27,16 +27,18 @@ def main_other_2(conn):
                 <li><a href="/old_page">''' + load_lang('old_page') + '''</a></li>
                 <li><a href="/image_file_list">''' + load_lang('image_file_list') + '''</a></li>
                 <li><a href="/vote">''' + load_lang('vote_list') + '''</a></li>
+                <li><a href="/long_page">''' + load_lang('long_page') + '''</a></li>
+                <!-- <li><a href="/short_page">''' + load_lang('short_page') + '''</a></li> -->
             </ul>
             <br>
             <h2>''' + load_lang('other') + '''</h2>
-            <ul>
+            <ul class="inside_ul">
                 <li><a href="/upload">''' + load_lang('upload') + '''</a></li>
                 <li><a href="/manager/10">''' + load_lang('search') + '''</a></li>
             </ul>
             <br>
             <h2>''' + load_lang('admin') + '''</h2>
-            <ul>
+            <ul class="inside_ul">
                 <li><a href="/manager/1">''' + load_lang('admin_tool') + '''</a></li>
             </ul>
         ''',

+ 12 - 14
route/main_views.py

@@ -11,24 +11,22 @@ def main_views_2(conn, name):
         file_name = file_name.group(1)
         dir_name = './views/' + re.sub(r'\.{2,}', '', re.sub(r'([^/]+)$', '', name))
 
-        mime_type = re.search(r'([^.]+)$', file_name)
-        image_type = [
-            '.jpeg', 
-            '.jpg', 
-            '.gif', 
-            '.png', 
-            '.webp'
-        ]
-        if mime_type:
-            mime_type = mime_type.group(1).lower()
+        mime_type = file_name.split('.')
+        if len(mime_type) < 2:
+            mime_type = 'text/plain'
+        else:
+            mime_type = mime_type[len(mime_type) - 1].lower()
+            image_type = ['jpeg', 'jpg', 'gif', 'png', 'webp']
             if mime_type in image_type:
                 mime_type = 'image/' + mime_type
+            elif mime_type == 'js':
+                mime_type = 'text/javascript'
+            elif mime_type == 'txt':
+                mime_type = 'text/plain'
             else:
                 mime_type = 'text/' + mime_type
-        else:
-            mime_type = 'text/plain'
-
+        
         return flask.send_from_directory(
             dir_name, file_name, 
             mimetype = mime_type
-        )
+        )

+ 36 - 69
route/recent_changes.py

@@ -34,29 +34,24 @@ def recent_changes_2(conn, name, tool):
                     <td id="main_table_width">''' + load_lang('time') + '''</td>
                 '''
 
-                tool_select = flask.request.args.get('tool', 'normal')
-                if tool_select == 'move':
-                    plus_sql = 'where (send like ? or send like ?) and type = "" '
-                    plus_list = ['%(<a>' + name +'</a>%', '%<a>' + name + '</a> move)', sql_num]
-                    sub += ' (' + load_lang('move') + ')'
-                elif tool_select == 'delete':
-                    plus_sql = 'where send like "%(delete)" and title = ? and type = "" '
-                    plus_list = [name, sql_num]
-                    sub += ' (' + load_lang('delete') + ')'
-                elif tool_select == 'revert':
-                    plus_sql = 'where send like ? and title = ? and type = "" '
-                    plus_list = ['%(r%)', name, sql_num]
-                    sub += ' (' + load_lang('revert') + ')'
+                set_type = flask.request.args.get('set', '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])
                 else:
-                    plus_sql = 'where title = ? and type = "" '
-                    plus_list = [name, sql_num]
+                    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 from history ' + \
-                    plus_sql + \
-                    'order by id + 0 desc ' + \
-                    "limit ?, 50" + \
-                ''), plus_list)
                 data_list = curs.fetchall()
             else:
                 div +=  '''
@@ -69,7 +64,7 @@ def recent_changes_2(conn, name, tool):
 
                 curs.execute(db_change('' + \
                     'select id, title, date, ip, send, leng, hide from history ' + \
-                    "where ip = ? and type = '' order by date desc limit ?, 50" + \
+                    "where ip = ? order by date desc limit ?, 50" + \
                 ''), [name, sql_num])
                 data_list = curs.fetchall()
         else:
@@ -80,41 +75,13 @@ def recent_changes_2(conn, name, tool):
             '''
             sub = ''
             set_type = flask.request.args.get('set', 'normal')
+            set_type = '' if set_type == 'edit' else set_type
 
-            if set_type != 'normal':
-                if set_type == 'move':
-                    plus_sql = 'where send like "%</a> move)" and '
-                    sub += ' (' + load_lang('move') + ')'
-                elif set_type == 'delete':
-                    plus_sql = 'where send like "%(delete)" and '
-                    sub += ' (' + load_lang('delete') + ')'
-                elif set_type == 'revert':
-                    plus_sql = 'where send like "%(r%)" and '
-                    sub += ' (' + load_lang('revert') + ')'
-                else:
-                    plus_sql = 'where '
-
-                plus_sql += 'type = "" '
-                
-                if set_type == 'user':
-                    plus_sql = 'where title like "user:%" '
-                    sub += ' (' + load_lang('user') + ')'
-                else:
-                    plus_sql += 'and not title like "user:%" '
-
-                curs.execute(db_change('' + \
-                    'select id, title, date, ip, send, leng, hide from history ' + \
-                    plus_sql + \
-                    'order by date desc ' + \
-                    'limit 50' + \
-                ''))
-                data_list = curs.fetchall()
-            else:
-                data_list = []
-                curs.execute(db_change('select id, title from rc order by date desc'))
-                for i in curs.fetchall():
-                    curs.execute(db_change('select id, title, date, ip, send, leng, hide from history where id = ? and title = ?'), i)
-                    data_list += curs.fetchall()
+            data_list = []
+            curs.execute(db_change('select id, title from rc where type = ? order by date desc'), [set_type])
+            for i in curs.fetchall():
+                curs.execute(db_change('select id, title, date, ip, send, leng, hide from history where id = ? and title = ?'), i)
+                data_list += curs.fetchall()
 
         div += '</tr>'
 
@@ -186,14 +153,17 @@ def recent_changes_2(conn, name, tool):
 
         if name:
             if tool == 'history':
-                if tool_select == 'normal':
-                    div = '' + \
-                        '<a href="?tool=move">(' + load_lang('move') + ')</a> ' + \
-                        '<a href="?tool=delete">(' + load_lang('delete') + ')</a> ' + \
-                        '<a href="?tool=revert">(' + load_lang('revert') + ')</a>' + \
-                        '<hr class="main_hr">' + div + \
-                    ''
-
+                div = '' + \
+                    '<a href="?set=normal">(' + load_lang('normal') + ')</a> ' + \
+                    '<a href="?set=edit">(' + load_lang('edit') + ')</a> ' + \
+                    '<a href="?set=move">(' + load_lang('move') + ')</a> ' + \
+                    '<a href="?set=delete">(' + load_lang('delete') + ')</a> ' + \
+                    '<a href="?set=revert">(' + load_lang('revert') + ')</a>' + \
+                    '<hr class="main_hr">' + div + \
+                ''
+                menu = [['w/' + url_pas(name), load_lang('return')]]
+                
+                if set_type == 'normal':
                     div = '''
                         <form method="post">
                             <select name="a">''' + select + '''</select> <select name="b">''' + select + '''</select>
@@ -202,15 +172,11 @@ def recent_changes_2(conn, name, tool):
                         <hr class=\"main_hr\">
                     ''' + div
 
-                    menu = [['w/' + url_pas(name), load_lang('return')]]
-
                     if admin == 1:
                         menu += [['add_history/' + url_pas(name), load_lang('history_add')]]
-                else:
-                    menu = [['history/' + url_pas(name), load_lang('return')]]
 
                 title = name
-                div += next_fix('/history/' + url_pas(name) + '?tool=' + tool_select + '&num=', num, data_list)
+                div += next_fix('/history/' + url_pas(name) + '?tool=' + set_type + '&num=', num, data_list)
             else:
                 title = load_lang('edit_record')
                 menu = [['other', load_lang('other')], ['user', load_lang('user')], ['count/' + url_pas(name), load_lang('count')]]
@@ -218,6 +184,7 @@ def recent_changes_2(conn, name, tool):
         else:
             div = '' + \
                 '<a href="?set=normal">(' + load_lang('normal') + ')</a> ' + \
+                '<a href="?set=edit">(' + load_lang('edit') + ')</a> ' + \
                 '<a href="?set=user">(' + load_lang('user_document') + ')</a> ' + \
                 '<a href="?set=move">(' + load_lang('move') + ')</a> ' + \
                 '<a href="?set=delete">(' + load_lang('delete') + ')</a> ' + \

+ 1 - 1
route/recent_history_tool.py

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

+ 6 - 12
route/search_deep.py

@@ -7,30 +7,24 @@ def search_deep_2(conn, name):
         return redirect()
 
     num = int(number_check(flask.request.args.get('num', '1')))
-    if num * 50 > 0:
-        sql_num = num * 50 - 50
-    else:
-        sql_num = 0
+    sql_num = (num * 50 - 50) if num * 50 > 0 else 0
 
-    div = '<ul>'
+    div = '<ul class="inside_ul">'
 
     div_plus = ''
     test = ''
 
     curs.execute(db_change("select title from data where title = ?"), [name])
-    if curs.fetchall():
-        link_id = ''
-    else:
-        link_id = 'id="not_thing"'
+    link_id = '' if curs.fetchall() else 'id="not_thing"'
 
     div = '''
-        <ul>
+        <ul class="inside_ul">
             <li>
                 <a ''' + link_id + ' href="/w/' + url_pas(name) + '">' + html.escape(name) + '''</a>
             </li>
         </ul>
         <hr class=\"main_hr\">
-        <ul>
+        <ul class="inside_ul">
     '''
 
     curs.execute(db_change('select data from other where name = "count_all_title"'))
@@ -48,7 +42,7 @@ def search_deep_2(conn, name):
 
             for data in all_list:
                 if data[1] != test:
-                    div_plus += '</ul><hr class=\"main_hr\"><ul>'
+                    div_plus += '</ul><hr class=\"main_hr\"><ul class="inside_ul">'
 
                     test = data[1]
 

+ 1 - 1
route/server_now_update.py

@@ -46,7 +46,7 @@ def server_now_update_2(conn, r_ver):
             imp = [load_lang('update'), wiki_set(), custom(), other2([0, 0])],
             data = load_lang('update_warring') + '''
                 <hr class=\"main_hr\">
-                <ul>
+                <ul class="inside_ul">
                     <li>''' + load_lang('version') + ' : ' + r_ver + '''</li>
                     <li id="ver_send" style="display: none;">''' + load_lang('lastest') + ''' : </li>
                 </ul>

+ 23 - 15
route/setting.py

@@ -28,7 +28,7 @@ def setting_2(conn, num, db_set):
 
         return easy_minify(flask.render_template(skin_check(),
             imp = [load_lang('setting'), wiki_set(), custom(), other2([0, 0])],
-            data = '<h2>' + load_lang('list') + '</h2><ul>' + li_data + '</ul>',
+            data = '<h2>' + load_lang('list') + '</h2><ul class="inside_ul">' + li_data + '</ul>',
             menu = [['manager', load_lang('return')]]
         ))
     elif num == 1:
@@ -50,7 +50,8 @@ def setting_2(conn, num, db_set):
             19 : 'slow_edit',
             20 : 'requires_approval',
             21 : 'backup_where',
-            22 : 'domain'
+            22 : 'domain',
+            23 : 'ua_get'
         }
         n_list = {
             0 : 'Wiki',
@@ -70,7 +71,8 @@ def setting_2(conn, num, db_set):
             19 : '0',
             20 : '',
             21 : '',
-            22 : flask.request.host_url
+            22 : flask.request.host_url,
+            23 : ''
         }
 
         if flask.request.method == 'POST':
@@ -108,16 +110,18 @@ def setting_2(conn, num, db_set):
                 else:
                     acl_div[0] += '<option value="' + acl_data + '">' + acl_data + '</option>'
 
-            check_box_div = ['', '', '', '']
-            for i in range(0, 4):
+            check_box_div = ['', '', '', '', '']
+            for i in range(0, len(check_box_div)):
                 if i == 0:
                     acl_num = 7
                 elif i == 1:
                     acl_num = 8
                 elif i == 2:
                     acl_num = 13
-                else:
+                elif i == 3:
                     acl_num = 20
+                else:
+                    acl_num = 23
 
                 if d_list[acl_num]:
                     check_box_div[i] = 'checked="checked"'
@@ -130,10 +134,7 @@ def setting_2(conn, num, db_set):
                 else:
                     branch_div += '<option value="' + i + '">' + i + '</option>'
 
-            if db_set != 'sqlite':
-                sqlite_only = 'style="display:none;"'
-            else:
-                sqlite_only = ''
+            sqlite_only = 'style="display:none;"' if db_set != 'sqlite' else ''
 
             return easy_minify(flask.render_template(skin_check(),
                 imp = [load_lang('main_setting'), wiki_set(), custom(), other2([0, 0])],
@@ -179,6 +180,8 @@ def setting_2(conn, num, db_set):
                         <hr class="main_hr">
                         <input type="checkbox" name="requires_approval" ''' + check_box_div[3] + '''> ''' + load_lang('requires_approval') + '''
                         <hr class="main_hr">
+                        <input type="checkbox" name="ua_get" ''' + check_box_div[4] + '''> ''' + load_lang('ua_get_off') + '''
+                        <hr class="main_hr">
                         <span>''' + load_lang('wiki_host') + '''</span>
                         <hr class="main_hr">
                         <input name="host" value="''' + html.escape(d_list[16]) + '''">
@@ -228,7 +231,8 @@ def setting_2(conn, num, db_set):
             'error_404',
             'approval_question',
             'edit_help',
-            'upload_help'
+            'upload_help',
+            'upload_default'
         ]
         if flask.request.method == 'POST':
             for i in i_list:
@@ -309,7 +313,7 @@ def setting_2(conn, num, db_set):
                         <hr class="main_hr">
                         <textarea rows="3" name="''' + i_list[11] + '''">''' + html.escape(d_list[11]) + '''</textarea>
                         <hr class="main_hr">
-                        <span>''' + load_lang('approval_question') + '''</span><sup><a href="#rfn-1" id="fn-1">(1)</a></sup>
+                        <span>''' + load_lang('approval_question') + '''</span><sup><a href="#note_1_end" id="note_1">(1)</a></sup>
                         <hr class="main_hr">
                         <textarea rows="3" name="''' + i_list[12] + '''">''' + html.escape(d_list[12]) + '''</textarea>
                         <hr class="main_hr">
@@ -317,14 +321,18 @@ def setting_2(conn, num, db_set):
                         <hr class="main_hr">
                         <textarea rows="3" name="''' + i_list[13] + '''">''' + html.escape(d_list[13]) + '''</textarea>
                         <hr class="main_hr">
-                        <span>''' + load_lang('upload_help') + '''</span>
+                        <span>''' + load_lang('upload_help') + ''' (HTML)</span>
                         <hr class="main_hr">
                         <textarea rows="3" name="''' + i_list[14] + '''">''' + html.escape(d_list[14]) + '''</textarea>
                         <hr class="main_hr">
+                        <span>''' + load_lang('upload_default') + '''</span>
+                        <hr class="main_hr">
+                        <textarea rows="3" name="''' + i_list[15] + '''">''' + html.escape(d_list[15]) + '''</textarea>
+                        <hr class="main_hr">
                         <button id="save" type="submit">''' + load_lang('save') + '''</button>
                         <hr class="main_hr">
-                        <ul>
-                            <li><a href="#fn-1" id="rfn-1">(1)</a> <span>''' + load_lang('approval_question_visible_only_when_approval_on') + '''</span></li>
+                        <ul id="footnote_data">
+                            <li><a href="#note_1" id="note_1_end">(1)</a> <span>''' + load_lang('approval_question_visible_only_when_approval_on') + '''</span></li>
                         </ul>
                     </form>
                 ''',

+ 213 - 151
route/tool/func.py

@@ -13,6 +13,8 @@ for i in range(0, 2):
         import tornado.wsgi
         import urllib.request
         import email.mime.text
+        import email.utils
+        import email.header
         import requests
         import sqlite3
         import pymysql
@@ -22,6 +24,7 @@ for i in range(0, 2):
         import zipfile
         import shutil
         import threading
+        import PIL
         import logging
         import random
         import flask
@@ -38,8 +41,11 @@ for i in range(0, 2):
             print(e)
             print('----')
             if platform.system() == 'Linux' or platform.system() == 'Windows':
-                ok = os.system('python' + ('3' if platform.system() != 'Windows' else '') + ' -m pip install --user -r requirements.txt')
-                if ok == 0:
+                sys_pip_ins = os.system(
+                    'python' + ('3' if platform.system() != 'Windows' else '') + ' ' + \
+                    '-m pip install --user -r requirements.txt'
+                )
+                if sys_pip_ins == 0:
                     print('----')
                     try:
                         os.execl(sys.executable, sys.executable, *sys.argv)
@@ -52,17 +58,18 @@ for i in range(0, 2):
                 else:
                     print('Error : library install failed')
                     raise
-            else:
-                print('----')
-                print(e)
-                raise
-        else:
-            print('----')
-            print(e)
-            raise
+            
+        print('----')
+        print(e)
+        raise
 
 global_lang = {}
-req_list = ''
+
+data_css_ver = '75'
+data_css = ''
+
+conn = ''
+curs = ''
 
 def load_conn(data):
     global conn
@@ -73,6 +80,17 @@ def load_conn(data):
 
     load_conn2(data)
 
+def http_warring():
+    return '''
+        <div id="http_warring_text"></div>
+        <script>
+            if(window.location.protocol !== 'https:') {
+                document.getElementById('http_warring_text').innerHTML = "''' + load_lang('http_warring') + '''";
+                document.getElementById('http_warring_text').style.margin = "10px 0px 0px 0px";
+            }
+        </script>
+    '''
+    
 def send_email(who, title, data):
     try:
         curs.execute(db_change('' + \
@@ -88,37 +106,37 @@ def send_email(who, title, data):
         smtp_port = ''
         smtp = ''
 
-        if rep_data:
-            smtp_email = ''
-            smtp_pass = ''
-            for i in rep_data:
-                if i[0] == 'smtp_email':
-                    smtp_email = i[1]
-                elif i[0] == 'smtp_pass':
-                    smtp_pass = i[1]
-                elif i[0] == 'smtp_server':
-                    smtp_server = i[1]
-                elif i[0] == 'smtp_security':
-                    smtp_security = i[1]
-                elif i[0] == 'smtp_port':
-                    smtp_port = i[1]
-            
-            smtp_port = int(smtp_port)
-            if smtp_security == 'plain':
-                smtp = smtplib.SMTP(smtp_server, smtp_port)
-            elif smtp_security == 'starttls':
-                smtp = smtplib.SMTP(smtp_server, smtp_port)
-                smtp.starttls()
-            else: # if smtp_security == 'tls':
-                smtp = smtplib.SMTP_SSL(smtp_server, smtp_port)
-            
-            smtp.login(smtp_email, smtp_pass)
+        for i in rep_data:
+            if i[0] == 'smtp_email':
+                smtp_email = i[1]
+            elif i[0] == 'smtp_pass':
+                smtp_pass = i[1]
+            elif i[0] == 'smtp_server':
+                smtp_server = i[1]
+            elif i[0] == 'smtp_security':
+                smtp_security = i[1]
+            elif i[0] == 'smtp_port':
+                smtp_port = i[1]
+        
+        smtp_port = int(smtp_port)
+        if smtp_security == 'plain':
+            smtp = smtplib.SMTP(smtp_server, smtp_port)
+        elif smtp_security == 'starttls':
+            smtp = smtplib.SMTP(smtp_server, smtp_port)
+            smtp.starttls()
         else:
-            raise
+            # if smtp_security == 'tls':
+            smtp = smtplib.SMTP_SSL(smtp_server, smtp_port)
+        
+        smtp.login(smtp_email, smtp_pass)
+
+        domain = load_domain()
 
         msg = email.mime.text.MIMEText(data)
         msg['Subject'] = title
-        smtp.sendmail(smtp_email, who, msg.as_string())
+        msg['From'] = email.utils.formataddr((str(email.header.Header(wiki_set()[0], 'utf-8')), 'noreply@' + domain))
+        msg['To'] = who
+        smtp.sendmail('noreply@' + domain, who, msg.as_string())
 
         smtp.quit()
 
@@ -130,6 +148,16 @@ def send_email(who, title, data):
 
         return 0
 
+def load_domain():
+    curs.execute(db_change("select data from other where name = 'domain'"))
+    domain = curs.fetchall()
+    domain = domain[0][0] if domain and domain[0][0] != '' else flask.request.host_url
+
+    return domain
+
+def load_random_key(long = 64):
+    return ''.join(random.choice("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") for i in range(long))
+
 def last_change(data):
     json_address = re.sub(r"(((?!\.|\/).)+)\.html$", "set.json", skin_check())
     try:
@@ -177,6 +205,8 @@ def render_set(title = '', data = '', num = 0, s_data = 0, include = None, acl =
         return data
     else:
         if data != None:
+            darkmode = flask.request.cookies.get('main_css_darkmode', '0')
+            
             return render_do(title, data, num, include)
         else:
             return 'HTTP Request 404'
@@ -233,7 +263,6 @@ def update(ver_num, set_data):
                 i[0]
             ])
 
-    # set 1
     if ver_num < 3190201:
         today_time = get_time()
 
@@ -270,7 +299,8 @@ def update(ver_num, set_data):
         if get_data and get_data[0][0] == 'master':
             curs.execute(db_change("update other set data = 'beta' where name = 'update'"), [])
 
-    if ver_num < 3202500:
+    # 캐시 초기화
+    if ver_num < 3206000:
         curs.execute(db_change('delete from cache_data'))
 
     if ver_num < 3202600:
@@ -290,9 +320,25 @@ def update(ver_num, set_data):
                 i[2]
             ])
 
+    if ver_num < 3203400:
+        curs.execute(db_change("select user, css from custom"))
+        for i in curs.fetchall():
+            curs.execute(db_change("insert into user_set (name, id, data) values ('custom_css', ?, ?)"), [
+                re.sub(r' \(head\)$', '', i[0]), 
+                i[1]
+            ])
+
+    if ver_num < 3205500:
+        curs.execute(db_change("select title, decu, dis, view, why from acl"))
+        for i in curs.fetchall():
+            curs.execute(db_change("insert into acl (title, data, type) values (?, ?, ?)"), [i[0], i[1], 'decu'])
+            curs.execute(db_change("insert into acl (title, data, type) values (?, ?, ?)"), [i[0], i[2], 'dis'])
+            curs.execute(db_change("insert into acl (title, data, type) values (?, ?, ?)"), [i[0], i[3], 'view'])
+            curs.execute(db_change("insert into acl (title, data, type) values (?, ?, ?)"), [i[0], i[4], 'why'])
+            
     conn.commit()
 
-    print('Update pass')
+    print('Update completed')
 
 def set_init():
     # 초기값 설정 함수    
@@ -311,7 +357,7 @@ def set_init():
         for i in [['smtp_server', 'smtp.gmail.com'], ['smtp_port', '587'], ['smtp_security', 'starttls']]:
             curs.execute(db_change("insert into other (name, data) values (?, ?)"), [i[0], i[1]])
 
-def pw_encode(data, data2 = '', type_d = ''):
+def pw_encode(data, type_d = ''):
     if type_d == '':
         curs.execute(db_change('select data from other where name = "encode"'))
         set_data = curs.fetchall()
@@ -338,16 +384,15 @@ def pw_check(data, data2, type_d = 'no', id_d = ''):
     else:
         set_data = db_data[0][0]
 
-    if pw_encode(data = data, type_d = set_data) == data2:
-        re_data = 1
-    else:
-        re_data = 0
-
+    re_data = 1 if pw_encode(data, set_data) == data2 else 0
     if db_data[0][0] != set_data and re_data == 1 and id_d != '':
         curs.execute(db_change("update user set pw = ?, encode = ? where id = ?"), [pw_encode(data), db_data[0][0], id_d])
 
     return re_data
 
+def add_alarm(who, context):
+    curs.execute(db_change('insert into alarm (name, data, date) values (?, ?, ?)'), [who, context, get_time()])
+
 def captcha_get():
     data = ''
 
@@ -404,32 +449,33 @@ def captcha_post(re_data, num = 1):
     else:
         pass
 
+def ua_plus(id, ip, ua, time):
+    curs.execute(db_change("select data from other where name = 'ua_get'"))
+    rep_data = curs.fetchall()
+    if rep_data and rep_data[0][0] != '':
+        pass
+    else:
+        curs.execute(db_change("insert into ua_d (name, ip, ua, today, sub) values (?, ?, ?, ?, '')"), [id, ip, ua, time])
+
 def load_lang(data, num = 2, safe = 0):
     global global_lang
 
-    if num == 1:
-        curs.execute(db_change("select data from other where name = 'language'"))
-        rep_data = curs.fetchall()
-        if rep_data:
-            try:
-                if not rep_data[0][0] in global_lang:
-                    lang = json.loads(open(os.path.join('language', rep_data[0][0] + '.json'), encoding='utf8').read())
-                    global_lang[rep_data[0][0]] = lang
-                else:
-                    lang = global_lang[rep_data[0][0]]
-            except:
-                return html.escape(data + ' (' + rep_data[0][0] + ')')
-
-            if data in lang:
-                return lang[data] if safe == 1 else html.escape(lang[data])
+    for i in range(0, 2):
+        if i == 0:
+            ip = ip_check()
+            if ip_or_user(ip) == 0:
+                curs.execute(db_change('select data from user_set where name = "lang" and id = ?'), [ip])
+                rep_data = curs.fetchall()
             else:
-                return html.escape(data + ' (' + rep_data[0][0] + ')')
+                if 'lang' in flask.session:
+                    rep_data = [[flask.session['lang']]]
+                else:
+                    continue
         else:
-            return html.escape(data + ' (' + rep_data[0][0] + ')')
-    else:
-        curs.execute(db_change('select data from user_set where name = "lang" and id = ?'), [ip_check()])
-        rep_data = curs.fetchall()
-        if rep_data and rep_data != '' and rep_data != 'default':
+            curs.execute(db_change("select data from other where name = 'language'"))
+            rep_data = curs.fetchall()
+        
+        if rep_data and rep_data[0][0] != '' and rep_data[0][0] != 'default':
             try:
                 if not rep_data[0][0] in global_lang:
                     lang = json.loads(open(os.path.join('language', rep_data[0][0] + '.json'), encoding='utf8').read())
@@ -437,14 +483,16 @@ def load_lang(data, num = 2, safe = 0):
                 else:
                     lang = global_lang[rep_data[0][0]]
             except:
-                return load_lang(data, 1, safe)
+                continue
 
             if data in lang:
                 return lang[data] if safe == 1 else html.escape(lang[data])
             else:
-                return load_lang(data, 1, safe)
+                continue
         else:
-            return load_lang(data, 1, safe)
+            continue
+    
+    return html.escape(data + ' (' + rep_data[0][0] + ')')
 
 def ip_or_user(data = ''):
     if data == '':
@@ -493,18 +541,27 @@ def ip_warring():
 
 def skin_check(set_n = 0):
     skin_list = load_skin('marisa', 1)
-
-    curs.execute(db_change('select data from user_set where name = "skin" and id = ?'), [ip_check()])
-    skin_exist = curs.fetchall()
-    if skin_exist and skin_exist[0][0] != '' and skin_exist[0][0] in skin_list:
-        skin = skin_exist[0][0]
-    else:
-        curs.execute(db_change('select data from other where name = "skin"'))
+    skin = skin_list[0]
+    check_list = []
+    ip = ip_check()
+    
+    if ip_or_user(ip) == 0:
+        curs.execute(db_change('select data from user_set where name = "skin" and id = ?'), [ip])
         skin_exist = curs.fetchall()
-        if skin_exist and skin_exist[0][0] != '' and skin_exist[0][0] in skin_list:
-            skin = skin_exist[0][0]
-        else:
-            skin = skin_list[0]
+        check_list += skin_exist
+    else:
+        if 'skin' in flask.session:
+            check_list += [[flask.session['skin']]]
+            
+    curs.execute(db_change('select data from other where name = "skin"'))
+    skin_exist = curs.fetchall()
+    check_list += skin_exist
+    
+    for i in check_list:
+        if i[0] != '' and i[0] in skin_list:
+            skin = i[0]
+            
+            break
 
     return './views/' + skin + '/index.html' if set_n == 0 else skin
 
@@ -531,18 +588,19 @@ def next_fix(link, num, page, end = 50):
     return list_data
 
 def other2(data):
-    global req_list
-    main_css_ver = '53'
+    global data_css
+    global data_css_ver
+
     data += ['' for _ in range(0, 3 - len(data))]
 
-    if req_list == '':
+    if data_css == '':
         for i_data in os.listdir(os.path.join("views", "main_css", "css")):
             if i_data != 'sub':
-                req_list += '<link rel="stylesheet" href="/views/main_css/css/' + i_data + '?ver=' + main_css_ver + '">'
+                data_css += '<link rel="stylesheet" href="/views/main_css/css/' + i_data + '?ver=' + data_css_ver + '">'
 
         for i_data in os.listdir(os.path.join("views", "main_css", "js")):
             if i_data != 'sub':
-                req_list += '<script src="/views/main_css/js/' + i_data + '?ver=' + main_css_ver + '"></script>'
+                data_css += '<script src="/views/main_css/js/' + i_data + '?ver=' + data_css_ver + '"></script>'
 
     data = data[0:2] + ['', '''
         <link   rel="stylesheet"
@@ -555,8 +613,7 @@ def other2(data):
                 integrity="sha384-g7c+Jr9ZivxKLnZTDUhnkOnsh30B4H0rpLUpJ4jAIKs4fnJI+sEnkvrMWph2EDg4"
                 crossorigin="anonymous"></script>
         <script src="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@10.1.2/build/highlight.min.js"></script>
-        <script>window.addEventListener('DOMContentLoaded', function() { main_css_skin_load(); });</script>
-    ''' + req_list] + data[2:]
+    ''' + data_css + '<script>window.addEventListener(\'DOMContentLoaded\', main_css_skin_load);</script>'] + data[2:]
 
     return data
 
@@ -578,22 +635,16 @@ def cut_100(data):
 
 def wiki_set(num = 1):
     if num == 1:
-        data_list = []
         skin_name = skin_check(1)
+        data_list = []
 
         curs.execute(db_change('select data from other where name = ?'), ['name'])
         db_data = curs.fetchall()
-        if db_data and db_data[0][0] != '':
-            data_list += [db_data[0][0]]
-        else:
-            data_list += ['Wiki']
+        data_list += [db_data[0][0]] if db_data and db_data[0][0] != '' else ['Wiki']
 
         curs.execute(db_change('select data from other where name = "license"'))
         db_data = curs.fetchall()
-        if db_data and db_data[0][0] != '':
-            data_list += [db_data[0][0]]
-        else:
-            data_list += ['ARR']
+        data_list += [db_data[0][0]] if db_data and db_data[0][0] != '' else ['ARR']
 
         data_list += ['', '']
 
@@ -604,53 +655,39 @@ def wiki_set(num = 1):
         else:
             curs.execute(db_change('select data from other where name = "logo" and coverage = ""'))
             db_data = curs.fetchall()
-            if db_data and db_data[0][0] != '':
-                data_list += [db_data[0][0]]
-            else:
-                data_list += [data_list[0]]
+            data_list += [db_data[0][0]] if db_data and db_data[0][0] != '' else [data_list[0]]
 
         head_data = ''
 
         curs.execute(db_change("select data from other where name = 'head' and coverage = ''"))
         db_data = curs.fetchall()
-        if db_data and db_data[0][0] != '':
-            head_data += db_data[0][0]
+        head_data += db_data[0][0] if db_data and db_data[0][0] != '' else ''
 
         curs.execute(db_change("select data from other where name = 'head' and coverage = ?"), [skin_name])
         db_data = curs.fetchall()
-        if db_data and db_data[0][0] != '':
-            head_data += db_data[0][0]
+        head_data += db_data[0][0] if db_data and db_data[0][0] != '' else ''
             
         data_list += [head_data]
-
-        return data_list
-
-    if num == 2:
-        var_data = 'FrontPage'
-
+    elif num == 2:
         curs.execute(db_change('select data from other where name = "frontpage"'))
+        db_data = curs.fetchall()
+        data_list = db_data[0][0] if db_data and db_data[0][0] != '' else 'FrontPage'
     elif num == 3:
-        var_data = '2'
-
         curs.execute(db_change('select data from other where name = "upload"'))
-
-    db_data = curs.fetchall()
-    if db_data and db_data[0][0] != '':
-        return db_data[0][0]
+        db_data = curs.fetchall()
+        data_list = db_data[0][0] if db_data and db_data[0][0] != '' else '2'
     else:
-        return var_data
+        data_list = ''
+
+    return data_list
 
 def admin_check(num = None, what = None, name = ''):
-    if name == '':
-        ip = ip_check()
-    else:
-        ip = name
+    ip = ip_check() if name == '' else name
+    time_data = get_time()
 
     curs.execute(db_change("select acl from user where id = ?"), [ip])
     user = curs.fetchall()
     if user:
-        reset = 0
-
         back_num = num
         while 1:
             if num == 1:
@@ -673,7 +710,7 @@ def admin_check(num = None, what = None, name = ''):
             curs.execute(db_change('select name from alist where name = ? and acl = ?'), [user[0][0], check])
             if curs.fetchall():
                 if what:
-                    curs.execute(db_change("insert into re_admin (who, what, time) values (?, ?, ?)"), [ip, what, get_time()])
+                    curs.execute(db_change("insert into re_admin (who, what, time) values (?, ?, ?)"), [ip, what, time_data])
                     conn.commit()
 
                 return 1
@@ -734,13 +771,15 @@ def ip_pas(raw_ip, type_d = 0):
     return ip if return_ip == 1 else end_ip
 
 def custom():
-    user_head = flask.session['head'] if 'head' in flask.session else ''
-
     ip = ip_check()
     if ip_or_user(ip) == 0:
         user_icon = 1
         user_name = ip
 
+        curs.execute(db_change("select data from user_set where id = ? and name = 'custom_css'"), [ip])
+        user_head = curs.fetchall()
+        user_head = user_head[0][0] if user_head else ''
+        
         curs.execute(db_change('select data from user_set where name = "email" and id = ?'), [ip])
         email = curs.fetchall()
         email = email[0][0] if email else ''
@@ -770,6 +809,7 @@ def custom():
         user_admin = '0'
         user_acl_list = '0'
         user_notice = '0'
+        user_head = flask.session['head'] if 'head' in flask.session else ''
 
     curs.execute(db_change("select title from rd where title = ? and stop = ''"), ['user:' + ip])
     user_topic = '1' if curs.fetchall() else '0'
@@ -854,12 +894,7 @@ def slow_edit_check():
 def acl_check(name = 'test', tool = '', topic_num = '1'):
     ip = ip_check()
     get_ban = ban_check()
-    
-    if name:
-        acl_c = re.search(r"^user:((?:(?!\/).)*)", name)
-    else:
-        acl_c = None
-
+    acl_c = re.search(r"^user:((?:(?!\/).)*)", name) if name else None
     if tool == '' and acl_c:
         acl_n = acl_c.groups()
 
@@ -869,7 +904,7 @@ def acl_check(name = 'test', tool = '', topic_num = '1'):
         if admin_check(5) == 1:
             return 0
 
-        curs.execute(db_change("select decu from acl where title = ?"), ['user:' + acl_n[0]])
+        curs.execute(db_change("select data from acl where title = ? and type = 'decu'"), ['user:' + acl_n[0]])
         acl_data = curs.fetchall()
         if acl_data:
             if acl_data[0][0] == 'all':
@@ -902,7 +937,7 @@ def acl_check(name = 'test', tool = '', topic_num = '1'):
     for i in range(0, end):
         if tool == '':
             if i == 0:
-                curs.execute(db_change("select decu from acl where title = ?"), [name])
+                curs.execute(db_change("select data from acl where title = ? and type = 'decu'"), [name])
             else:
                 curs.execute(db_change('select data from other where name = "edit"'))
 
@@ -911,7 +946,7 @@ def acl_check(name = 'test', tool = '', topic_num = '1'):
             if i == 0 and topic_num:
                 curs.execute(db_change("select acl from rd where code = ?"), [topic_num])
             elif i == 1:
-                curs.execute(db_change("select dis from acl where title = ?"), [name])
+                curs.execute(db_change("select data from acl where title = ? and type = 'dis'"), [name])
             else:
                 curs.execute(db_change('select data from other where name = "discussion"'))
 
@@ -929,10 +964,12 @@ def acl_check(name = 'test', tool = '', topic_num = '1'):
                 curs.execute(db_change('select acl from vote where id = ? and user = ""'), [topic_num])
             else:
                 curs.execute(db_change('select data from other where name = "vote_acl"'))
+
+            num = None
         else:
             # tool == 'render'
             if i == 0:
-                curs.execute(db_change("select view from acl where title = ?"), [name])
+                curs.execute(db_change("select data from acl where title = ? and type = 'view'"), [name])
             else:
                 curs.execute(db_change("select data from other where name = 'all_view_acl'"))
 
@@ -1104,23 +1141,25 @@ def rd_plus(topic_num, date, name = None, sub = None):
 
     conn.commit()
 
-def history_plus(title, data, date, ip, send, leng, t_check = '', d_type = '', mode = ''):
+def history_plus(title, data, date, ip, send, leng, t_check = '', mode = ''):
     if mode == 'add':
-        curs.execute(db_change("select id from history where title = ? and type = '' order by id + 0 asc limit 1"), [title])
+        curs.execute(db_change("select id from history where title = ? order by id + 0 asc limit 1"), [title])
         id_data = curs.fetchall()
         id_data = str(int(id_data[0][0]) - 1) if id_data else '0'
     else:
-        curs.execute(db_change("select id from history where title = ? and type = '' order by id + 0 desc limit 1"), [title])
+        curs.execute(db_change("select id from history where title = ? order by id + 0 desc limit 1"), [title])
         id_data = curs.fetchall()
         id_data = str(int(id_data[0][0]) + 1) if id_data else '1'
+        
+        mode = mode if not re.search('^user:', title) else 'user'
 
     send = re.sub(r'\(|\)|<|>', '', send)
     send = send[:128] if len(send) > 128 else send
     send = send + ' (' + t_check + ')' if t_check != '' else send
 
-    if not re.search('^user:', title) and mode != 'add':
+    if mode != 'add' and mode != 'user':
         curs.execute(db_change("select count(*) from rc where type = 'normal'"))
-        if curs.fetchall()[0][0] > 49:
+        if curs.fetchall()[0][0] >= 200:
             curs.execute(db_change("select id, title from rc where type = 'normal' order by date asc limit 1"))
             rc_data = curs.fetchall()
             if rc_data:
@@ -1128,13 +1167,32 @@ def history_plus(title, data, date, ip, send, leng, t_check = '', d_type = '', m
                     rc_data[0][0],
                     rc_data[0][1]
                 ])
-        
+    
         curs.execute(db_change("insert into rc (id, title, date, type) values (?, ?, ?, 'normal')"), [
             id_data,
             title,
             date
         ])
-
+    
+    if mode != 'add':
+        curs.execute(db_change("select count(*) from rc where type = ?"), [mode])
+        if curs.fetchall()[0][0] >= 200:
+            curs.execute(db_change("select id, title from rc where type = ? order by date asc limit 1"), [mode])
+            rc_data = curs.fetchall()
+            if rc_data:
+                curs.execute(db_change('delete from rc where id = ? and title = ? and type = ?'), [
+                    rc_data[0][0],
+                    rc_data[0][1],
+                    mode
+                ])
+    
+        curs.execute(db_change("insert into rc (id, title, date, type) values (?, ?, ?, ?)"), [
+            id_data,
+            title,
+            date,
+            mode
+        ])
+            
     curs.execute(db_change("insert into history (id, title, data, date, ip, send, leng, hide, type) values (?, ?, ?, ?, ?, ?, ?, '', ?)"), [
         id_data,
         title,
@@ -1143,7 +1201,7 @@ def history_plus(title, data, date, ip, send, leng, t_check = '', d_type = '', m
         ip,
         send,
         leng,
-        d_type
+        mode
     ])
 
 def leng_check(first, second):
@@ -1182,8 +1240,8 @@ def edit_filter_do(data):
     return 0
 
 def redirect(data = '/'):
-    return flask.redirect(data)
-
+    return flask.redirect(flask.request.host_url[:-1] + data)
+    
 def get_acl_list(type_d = 'normal'):
     if type_d == 'user':
         return ['', 'user', 'all']
@@ -1197,7 +1255,7 @@ def re_error(data):
         if ban_check() == 1:
             end = '<div id="get_user_info"></div><script>load_user_info("' + ip_check() + '");</script>'
         else:
-            end = '<ul><li>' + load_lang('authority_error') + '</li></ul>'
+            end = '<ul class="inside_ul"><li>' + load_lang('authority_error') + '</li></ul>'
 
         return easy_minify(flask.render_template(skin_check(),
             imp = [load_lang('error'), wiki_set(1), custom(), other2([0, 0])],
@@ -1271,6 +1329,10 @@ def re_error(data):
             data = load_lang('restart_fail_error')
         elif num == 34:
             data = load_lang("update_error") + ' <a href="https://github.com/2DU/opennamu">(Github)</a>'
+        elif num == 35:
+            data = load_lang('same_email_error')
+        elif num == 36:
+            data = load_lang('input_email_error')
         else:
             data = '???'
 
@@ -1282,7 +1344,7 @@ def re_error(data):
                 data = '' + \
                     '<div id="main_skin_set">' + \
                         '<h2>' + load_lang('error') + '</h2>' + \
-                        '<ul>' + \
+                        '<ul class="inside_ul">' + \
                             '<li>' + data + ' <a href="/main_skin_set">(' + load_lang('main_skin_set') + ')</a></li>' + \
                         '</ul>' + \
                     '</div>' + \
@@ -1292,6 +1354,6 @@ def re_error(data):
         else:
             return easy_minify(flask.render_template(skin_check(),
                 imp = [load_lang('error'), wiki_set(1), custom(), other2([0, 0])],
-                data = '<h2>' + load_lang('error') + '</h2><ul><li>' + data + '</li></ul>',
+                data = '<h2>' + load_lang('error') + '</h2><ul class="inside_ul"><li>' + data + '</li></ul>',
                 menu = 0
             )), 400

+ 1 - 1
route/tool/init.py

@@ -29,7 +29,7 @@ server_set_var = {
         'display' : 'Markup',
         'require' : 'select',
         'default' : 'namumark',
-        'list' : ['namumark', 'markdown', 'custom', 'raw']
+        'list' : ['namumark', 'custom', 'js_onmark']
     },
     'encode' : {
         'display' : 'Encryption method',

+ 27 - 19
route/tool/mark.py

@@ -1,7 +1,5 @@
-from .set_mark.namumark import namumark
-from .set_mark.markdown import markdown
-
-from .set_mark.tool import *
+from .namumark import namumark
+from .tool import *
 
 import re
 import os
@@ -11,8 +9,11 @@ import asyncio
 import threading
 import urllib.parse
 
-if os.path.exists('route/tool/set_mark/custom.py'):
-    from .set_mark.custom import custom_mark
+conn = ''
+curs = ''
+
+if os.path.exists('route/tool/custom.py'):
+    from .custom import custom_mark
 else:
     def custom_mark(conn, data, title, num, include):
         return [data, '', []]
@@ -39,33 +40,40 @@ def send_parser(data):
     return data
 
 def render_do(title, data, num, include):
-    if num == 3:
-        num = 1
-        back_num = 3
-    else:
-        back_num = num
-
+    # num == 1 -> commit O | html
+    # num == 2 -> commit X | list
+    # num == 3 -> commit X 
     curs.execute(db_change('select data from other where name = "markup"'))
     rep_data = curs.fetchall()
     if rep_data[0][0] == 'namumark':
         data = namumark(conn, data, title, include)
-    elif rep_data[0][0] == 'markdown':
-        data = markdown(conn, data, title, include)
     elif rep_data[0][0] == 'custom':
         data = custom_mark(conn, data, title, include)
-    elif rep_data[0][0] == 'raw':
-        data = [data, '', []]
+    elif rep_data[0][0] == 'js_onmark':
+        include = (include + '_') if include else ''
+        data = [
+            '<div id="' + include + 'render_content">' + html.escape(data) + '</div>', 
+            '''
+                do_onmark_render(
+                    test_mode = 0, 
+                    name_id = "''' + include + '''render_content",
+                    name_include = "''' + include + '''",
+                    name_doc = "''' + title.replace('"', '//"') + '''",
+                );
+            ''',
+            []
+        ]
     else:
-        data = ['', '', []]
+        data = [data, '', []]
 
-    if num == 1:
+    if num in [1, 3]:
         if data[2] == []:
             curs.execute(db_change("insert into back (title, link, type) values ('test', ?, 'nothing')"), [title])
         else:
             curs.executemany(db_change("insert into back (link, title, type) values (?, ?, ?)"), data[2])
             curs.execute(db_change("delete from back where title = ? and type = 'no'"), [title])
 
-        if back_num != 3:
+        if num != 3:
             conn.commit()
 
     if num == 2:

+ 39 - 25
route/tool/set_mark/namumark.py → route/tool/namumark.py

@@ -4,6 +4,11 @@ import datetime
 import html
 import re
 
+end_data = ''
+plus_data = ''
+nowiki_num = ''
+include_name = ''
+
 def nowiki_js(data):
     data = data.replace('\\', '\\\\')
     data = data.replace('"', '\\"')
@@ -396,17 +401,16 @@ def middle_parser(data):
                         ''
                         data = re.sub(
                             r'{{{#!folding ?((?:(?!\n).)*)\n?', '' + \
-                            '<div>' + \
-                                '<div style="display: inline-block;">' + \
-                                    '<b>' + \
-                                        '<a href="javascript:void(0);" ' + \
-                                            'onclick="do_open_folding(\'' + include_name + 'folding_' + str(folding_num) + '\');" ' + \
-                                            'id="get_' + include_name + 'folding_' + str(folding_num) + '">' + \
-                                        '</a>' + \
-                                    '</b>' + \
-                                '</div_2>' + \
-                                '<div id="' + include_name + 'folding_' + str(folding_num) + '" style="display: none;">' + \
-                                    '<div_1 style="">\n',
+                            '<div style="display: inline-block;">' + \
+                                '<b>' + \
+                                    '<a href="javascript:void(0);" ' + \
+                                        'onclick="do_open_folding(\'' + include_name + 'folding_' + str(folding_num) + '\');" ' + \
+                                        'id="get_' + include_name + 'folding_' + str(folding_num) + '">' + \
+                                    '</a>' + \
+                                '</b>' + \
+                            '</div_2>' + \
+                            '<div id="' + include_name + 'folding_' + str(folding_num) + '" style="display: none;">' + \
+                                '<div_1 style="">\n',
                             data,
                             1
                         )
@@ -444,7 +448,7 @@ def middle_parser(data):
                         middle_num -= 1
 
                     if middle_list[middle_num] == 'div_dd':
-                        data = middle_re.sub('</div_1></div_2></div_2>', data, 1)
+                        data = middle_re.sub('</div_1></div_2>', data, 1)
                     elif middle_list[middle_num] == 'pre':
                         data = middle_re.sub('</code></pre>', data, 1)
                     else:
@@ -465,8 +469,8 @@ def middle_parser(data):
                 if middle_num > 0:
                     middle_num -= 1
 
-                if middle_list[middle_num] == '2div':
-                    data += '</div_1></div_2></div_2>'
+                if middle_list[middle_num] == 'div_dd':
+                    data += '</div_1></div_2>'
                 elif middle_list[middle_num] == 'pre':
                     data += '</code></pre>'
                 else:
@@ -652,7 +656,14 @@ def namumark(conn, data, title, include_num):
                     else:
                         break
 
-                plus_data += 'load_include("' + include_link + '", "' + include_name + 'include_' + str(i) + '", ' + str(include_plus_data) + ');\n'
+                plus_data += '' + \
+                    'load_include(' + \
+                        '"' + include_link + '", '+ \
+                        '"' + include_name + 'include_' + str(i) + '", ' + \
+                        str(include_plus_data) + ', ' + \
+                        '"' + title + '"' + \
+                    ');\n' + \
+                ''
             else:
                 break
     else:
@@ -696,20 +707,21 @@ def namumark(conn, data, title, include_num):
         
         plus_data += '' + \
             'var get_link = window.location.search.match(/(?:\?|&)from=([^&]+)/);\n' + \
-            'var get_link_2 = window.location.pathname.match(/^\/w\//);' + \
+            'var get_link_2 = window.location.pathname.match(/^\/w\//);\n' + \
             'if(!get_link && get_link_2) {\n' + \
                 'window.location.href = "/w/' + tool.url_pas(main_link) + '?from=' + tool.url_pas(title) + other_link + '";\n' + \
             '}\n' + \
         ''
         data = redirect_re.sub('\nredirect to ' + html.escape(main_link) + other_link, data, 1)
 
-    no_toc_re = re.compile(r'\[(?:목차|toc)\((?:no)\)\]\n', re.I)
+    no_toc_re = re.compile(r'\[(?:목차|toc)\(no\)\]', re.I)
     toc_re = re.compile(r'\[(?:목차|toc)\]', re.I)
-    if not no_toc_re.search(data):
-        if not toc_re.search(data):
-            data = re.sub(r'(?P<in>\n(={1,6})(#)? ?((?:(?!(?: #=| =)).)+) ?#?(?:=+)\n)', '\n[toc]\g<in>', data, 1)
+    if not no_toc_re.search(data) and not toc_re.search(data):
+        data = re.sub(r'(?P<in>\n(={1,6})(#)? ?((?:(?!(?: #=| =)).)+) ?#?(?:=+)\n)', '\n[toc]\g<in>', data, 1)
+        auto_toc = 1
     else:
         data = no_toc_re.sub('', data)
+        auto_toc = 0
 
     data = '<div class="all_in_data" id="in_data_0">' + data
 
@@ -746,7 +758,7 @@ def namumark(conn, data, title, include_num):
                 '<h' + toc_len_str + ' id="s-' + toc_level_str + '">' + \
                     '<a href="#toc">' + toc_level_str + '.</a> ' + toc[2] + ' ' + \
                     '<span style="font-size: 12px">' + \
-                        '<a href="/edit/' + tool.url_pas(title) + '?section=' + edit_num_str + '">(Edit)</a>' + \
+                        '<a id="edit_load_' + edit_num_str + '" href="/edit/' + tool.url_pas(title) + '?section=' + edit_num_str + '">(Edit)</a>' + \
                         ' ' + \
                         '<a href="javascript:void(0);" onclick="do_open_folding(\'in_data_' + edit_num_str + '\', this);">' + \
                             '(' + toc_fol + ')' + \
@@ -773,7 +785,10 @@ def namumark(conn, data, title, include_num):
             break
 
     toc_data += '</div>'
-    data = toc_re.sub(toc_data, data)
+    if auto_toc == 1:
+        data = toc_re.sub('<div id="auto_toc">' + toc_data + '</div>', data, 1)
+    else:
+        data = toc_re.sub(toc_data, data)
     
     macro_re = re.compile(r'\[([^[(]+)\(((?:(?!\[|\)]).)+)\)\]')
     macro_data = macro_re.findall(data)
@@ -1033,7 +1048,6 @@ def namumark(conn, data, title, include_num):
                     main_link = category_re.sub('category:', main_link)
                     link_id = ''
 
-                    curs.execute(tool.db_change("select title from data where title = ?"), [main_link])
                     if re.search(r'#blur', main_link):
                         link_id = ' hidden_link'
                         main_link = main_link.replace('#blur', '')
@@ -1169,9 +1183,9 @@ def namumark(conn, data, title, include_num):
         else:
             break
 
-    if re.search(r'\[pagecount\]', data, flags = re.I):
+    if re.search(r'\[pagecount(?:\([^()]+\))?\]', data, flags = re.I):
         plus_data += 'page_count();\n'
-        data = re.sub(r'\[pagecount\]', '<span class="all_page_count"></span>', data, flags = re.I)
+        data = re.sub(r'\[pagecount(?:\([^()]+\))?\]', '<span class="all_page_count"></span>', data, flags = re.I)
 
     data = re.sub(r'\[date\]', now_time, data, flags = re.I)
     data = re.sub(r'\[clearfix\]', '<div style="clear:both"></div>', data, flags = re.I)

+ 0 - 136
route/tool/set_mark/markdown.py

@@ -1,136 +0,0 @@
-from . import tool
-
-import datetime
-import html
-import re
-
-class head_render:
-    def __init__(self):
-        self.head_level = [0, 0, 0, 0, 0, 0]
-        self.toc_data = '' + \
-            '<div id="toc">' + \
-                '<span id="toc_title">TOC</span>' + \
-                '<br>' + \
-                '<br>' + \
-        ''
-        self.toc_num = 0
-
-    def __call__(self, match):
-        head_len_num = len(match[1])
-        head_len = str(head_len_num)
-        head_len_num -= 1
-        head_data = match[2]
-        self.head_level[head_len_num] += 1
-        for i in range(head_len_num + 1, 6):
-            self.head_level[i] = 0
-            
-        self.toc_num += 1
-        toc_num_str = str(self.toc_num)
-        head_level_str_2 = '.'.join([str(i) for i in self.head_level if i != 0])
-        head_level_str = head_level_str_2 + '.'
-
-        self.toc_data += '<a href="#s-' + head_level_str_2 + '">' + head_level_str + '</a> ' + head_data + '<br>'
-        return '<h' + head_len + ' id="s-' + head_level_str_2 + '"><a href="#toc">' + head_level_str + '</a> ' + head_data + '</h' + head_len + '>'
-
-    def get_toc(self):
-        return self.toc_data + '</div>'
-
-class link_render:
-    def __init__(self, plus_data, include_name):
-        self.str_e_link_id = 0
-        self.plus_data = ''
-        self.include_name = include_name
-
-    def __call__(self, match):
-        str_e_link_id = str(self.str_e_link_id)
-        self.str_e_link_id += 1
-
-        if match[1] == '!':    
-            file_name = ''
-            if re.search(r'^http(s)?:\/\/', match[3], flags = re.I):
-                file_src = match[3]
-                file_alt = match[3]
-                exist = '1'
-            else:
-                file_name = re.search(r'^([^.]+)\.([^.]+)$', match[3])
-                if file_name:
-                    file_end = file_name.group(2)
-                    file_name = file_name.group(1)
-                else:
-                    file_name = 'Test'
-                    file_end = 'jpg'
-
-                file_src = '/image/' + tool.sha224_replace(file_name) + '.' + file_end
-                file_alt = 'file:' + file_name + '.' + file_end
-                exist = None
-
-            return '' + \
-                '<span  class="' + self.include_name + 'file_finder" ' + \
-                        'under_alt="' + file_alt + '" ' + \
-                        'under_src="' + file_src + '" ' + \
-                        'under_style="" ' + \
-                        'under_href="' + ("out_link" if exist else '/upload?name=' + tool.url_pas(file_name)) + '">' + \
-                '</span>' + \
-            ''
-        else:
-            if re.search(r'^http(s)?:\/\/', match[3], flags = re.I):
-                self.plus_data += '' + \
-                    'document.getElementsByName("' + self.include_name + 'set_link_' + str_e_link_id + '")[0].href = ' + \
-                        '"' + match[3] + '";' + \
-                    '\n' + \
-                ''
-
-                return '<a  id="out_link" ' + \
-                            'href="" ' + \
-                            'name="' + self.include_name + 'set_link_' + str_e_link_id + '">' + match[2] + '</a>'
-            else:
-                self.plus_data += '' + \
-                    'document.getElementsByName("' + self.include_name + 'set_link_' + str_e_link_id + '")[0].href = ' + \
-                        '"/w/' + tool.url_pas(match[3]) + '";' + \
-                    '\n' + \
-                ''
-                self.plus_data += '' + \
-                    'document.getElementsByName("' + self.include_name + 'set_link_' + str_e_link_id + '")[0].title = ' + \
-                        '"' + match[3] + '";' + \
-                    '\n' + \
-                ''
-
-                return '<a  class="' + self.include_name + 'link_finder" ' + \
-                            'title="" ' + \
-                            'href="" ' + \
-                            'name="' + self.include_name + 'set_link_' + str_e_link_id + '">' + match[2] + '</a>'
-
-    def get_plus_data(self):
-        return self.plus_data
-
-def markdown(conn, data, title, include_name):
-    backlink = []
-    include_name = include_name + '_' if include_name else ''
-    plus_data = '' + \
-        'get_link_state("' + include_name + '");\n' + \
-        'get_file_state("' + include_name + '");\n' + \
-    ''
-
-    data = html.escape(data)
-    data = data.replace('\r\n', '\n')
-    data = '\n' + data
-
-    head_r = r'\n(#{1,6}) ?([^\n]+)'
-    head_do = head_render()
-    data = re.sub(head_r, head_do, data)
-    data = head_do.get_toc() + data
-
-    link_r = r'(!)?\[((?:(?!\]\().)+)\]\(([^\]]+)\)'
-    link_do = link_render(plus_data, include_name)
-    data = re.sub(link_r, link_do, data)
-    plus_data = link_do.get_plus_data() + plus_data
-
-    data = re.sub(r'\*\*(?P<A>(?:(?!\*\*).)+)\*\*', '<b>\g<A></b>', data)
-    data = re.sub(r'__(?P<A>(?:(?!__).)+)__', '<i>\g<A></i>', data)
-
-    data = re.sub('^\n', '', data)
-    data = data.replace('\n', '<br>')
-
-    data = re.sub(r'(?P<A><\/h[0-6]>)<br>', '\g<A>', data)
-    
-    return [data, plus_data, backlink]

+ 3 - 1
route/tool/set_mark/tool.py → route/tool/tool.py

@@ -4,6 +4,8 @@ import hashlib
 import flask
 import re
 
+set_data = ''
+
 def get_time():
     return str(datetime.datetime.today().strftime("%Y-%m-%d %H:%M:%S"))
 
@@ -44,4 +46,4 @@ def sha224_replace(data):
     return hashlib.sha224(bytes(data, 'utf-8')).hexdigest()
 
 def md5_replace(data):
-    return hashlib.md5(data.encode()).hexdigest()
+    return hashlib.md5(data.encode()).hexdigest()

+ 28 - 55
route/topic.py

@@ -2,8 +2,6 @@ from .tool.func import *
 
 def topic_2(conn, topic_num):
     curs = conn.cursor()
-
-    admin = admin_check(3)
     topic_num = str(topic_num)
 
     if flask.request.method == 'POST':
@@ -37,38 +35,30 @@ def topic_2(conn, topic_num):
 
         curs.execute(db_change("select id from topic where code = ? order by id + 0 desc limit 1"), [topic_num])
         old_num = curs.fetchall()
-        if old_num:
-            num = int(old_num[0][0]) + 1
-        else:
-            num = 1
-
-        num = str(num)
+        num = str((int(old_num[0][0]) + 1) if old_num else 1)
 
         match = re.search(r'^user:([^/]+)', name)
         if match:
+            match = match.group(1)
             y_check = 0
-            if ip_or_user(match.group(1)) == 1:
-                curs.execute(db_change("select ip from history where ip = ? limit 1"), [match.group(1)])
+            if ip_or_user(match) == 1:
+                curs.execute(db_change("select ip from history where ip = ? limit 1"), [match])
                 u_data = curs.fetchall()
                 if u_data:
                     y_check = 1
                 else:
-                    curs.execute(db_change("select ip from topic where ip = ? limit 1"), [match.group(1)])
+                    curs.execute(db_change("select ip from topic where ip = ? limit 1"), [match])
                     u_data = curs.fetchall()
                     if u_data:
                         y_check = 1
             else:
-                curs.execute(db_change("select id from user where id = ?"), [match.group(1)])
+                curs.execute(db_change("select id from user where id = ?"), [match])
                 u_data = curs.fetchall()
                 if u_data:
                     y_check = 1
 
             if y_check == 1:
-                curs.execute(db_change('insert into alarm (name, data, date) values (?, ?, ?)'), [
-                    match.group(1),
-                    ip + ' | <a href="/thread/' + topic_num + '#' + num + '">' + name + ' | ' + sub + ' | #' + num + '</a>',
-                    today
-                ])
+                add_alarm(match, ip + ' | <a href="/thread/' + topic_num + '#' + num + '">' + name + ' | ' + sub + ' | #' + num + '</a>')
 
         cate_re = re.compile(r'\[\[((?:분류|category):(?:(?:(?!\]\]).)*))\]\]', re.I)
         data = cate_re.sub('[br]', flask.request.form.get('content', 'Test').replace('\r', ''))
@@ -77,11 +67,7 @@ def topic_2(conn, topic_num):
             curs.execute(db_change("select ip from topic where code = ? and id = ?"), [topic_num, rd_data])
             ip_data = curs.fetchall()
             if ip_data and ip_or_user(ip_data[0][0]) == 0:
-                curs.execute(db_change('insert into alarm (name, data, date) values (?, ?, ?)'), [
-                    ip_data[0][0],
-                    ip + ' | <a href="/thread/' + topic_num + '#' + num + '">' + name + ' | ' + sub + ' | #' + num + '</a>',
-                    today
-                ])
+                add_alarm(ip_data[0][0], ip + ' | <a href="/thread/' + topic_num + '#' + num + '">' + name + ' | ' + sub + ' | #' + num + '</a>')
 
         for rd_data in re.findall(r"(?: |\n|^)@((?:[^ ]+))(?: |\n|$)", data):
             curs.execute(db_change("select ip from history where ip = ? limit 1"), [rd_data])
@@ -91,11 +77,7 @@ def topic_2(conn, topic_num):
                 ip_data = curs.fetchall()
 
             if ip_data and ip_or_user(ip_data[0][0]) == 0:
-                curs.execute(db_change('insert into alarm (name, data, date) values (?, ?, ?)'), [
-                    ip_data[0][0],
-                    ip + ' | <a href="/thread/' + topic_num + '#' + num + '">' + name + ' | ' + sub + ' | #' + num + '</a>',
-                    today
-                ])
+                add_alarm(ip_data[0][0], ip + ' | <a href="/thread/' + topic_num + '#' + num + '">' + name + ' | ' + sub + ' | #' + num + '</a>')
 
         data = re.sub(r"( |\n|^)(#(?:[0-9]+))( |\n|$)", '\g<1><topic_a>\g<2></topic_a>\g<3>', data)
         data = re.sub(r"( |\n|^)(@(?:[^ ]+))( |\n|$)", '\g<1><topic_call>\g<2></topic_call>\g<3>', data)
@@ -112,37 +94,28 @@ def topic_2(conn, topic_num):
 
         return redirect('/thread/' + topic_num + '#' + num)
     else:
-        data = ''
-
-        if ban == 1:
-            display = 'display: none;'
-        else:
-            display = ''
-
-        data += '''
-            <div id="top_topic"></div>
-            <div id="main_topic"></div>
-            <div id="plus_topic"></div>
-            <script>topic_top_load("''' + topic_num + '''");</script>
-            <a href="/thread/''' + topic_num + '/tool">(' + load_lang('topic_tool') + ''')</a>
-            <hr class=\"main_hr\">
-            <form style="''' + display + '''" method="post">
-                <textarea id="content" class="topic_content" placeholder="''' + load_lang('content') + '''" name="content"></textarea>
-                <hr class=\"main_hr\">
-                ''' + captcha_get() + (ip_warring() if display == '' else '') + '''
-                <input style="display: none;" name="topic" value="''' + name + '''">
-                <input style="display: none;" name="title" value="''' + sub + '''">
-                <button id="save" type="submit">''' + load_lang('send') + '''</button>
-                <button id="preview" type="button" onclick="load_preview(\'\')">''' + load_lang('preview') + '''</button>
-            </form>
-            <hr class=\"main_hr\">
-            <div id="see_preview"></div>
-        '''
-
+        display = 'display: none;' if ban == 1 else ''
         return easy_minify(flask.render_template(skin_check(),
             imp = [name, wiki_set(), custom(), other2(['(' + load_lang('discussion') + ')', 0])],
             data = '''
                 <h2 id="topic_top_title">''' + html.escape(sub) + '''</h2>
-                ''' + data,
+                <div id="top_topic"></div>
+                <div id="main_topic"></div>
+                <div id="plus_topic"></div>
+                <script>new_topic_load("''' + topic_num + '''");</script>
+                <a href="/thread/''' + topic_num + '/tool">(' + load_lang('topic_tool') + ''')</a>
+                <hr class="main_hr">
+                <form style="''' + display + '''" method="post">
+                    <textarea id="content" class="topic_content" placeholder="''' + load_lang('content') + '''" name="content"></textarea>
+                    <hr class="main_hr">
+                    ''' + captcha_get() + (ip_warring() if display == '' else '') + '''
+                    <input style="display: none;" name="topic" value="''' + name + '''">
+                    <input style="display: none;" name="title" value="''' + sub + '''">
+                    <button id="save" type="submit">''' + load_lang('send') + '''</button>
+                    <button id="preview" type="button" onclick="load_preview(\'\')">''' + load_lang('preview') + '''</button>
+                </form>
+                <hr class="main_hr">
+                <div id="see_preview"></div>
+            ''',
             menu = [['topic/' + url_pas(name), load_lang('list')]]
         ))

+ 3 - 3
route/topic_admin.py

@@ -13,13 +13,13 @@ def topic_admin_2(conn, topic_num, num):
 
     ban = '''
         <h2>''' + load_lang('state') + '''</h2>
-        <ul>
+        <ul class="inside_ul">
             <li>''' + load_lang('writer') + ' : ''' + ip_pas(data[0][1]) + '''</li>
             <li>''' + load_lang('time') + ' : ' + data[0][2] + '''</li>
         </ul>
         <br>
         <h2>''' + load_lang('other_tool') + '''</h2>
-        <ul>
+        <ul class="inside_ul">
             <li>
                 <a href="/thread/''' + topic_num + '/raw/' + num + '''">''' + load_lang('raw') + '''</a>
             </li>
@@ -36,7 +36,7 @@ def topic_admin_2(conn, topic_num, num):
         ban += '''
             <br>
             <h2>''' + load_lang('admin_tool') + '''</h2>
-            <ul>
+            <ul class="inside_ul">
                 <li>
                     <a href="/ban/''' + url_pas(data[0][1]) + '''">
                         ''' + (load_lang('release') if user_ban_d else load_lang('ban')) + '''

+ 10 - 14
route/topic_close_list.py

@@ -35,39 +35,35 @@ def topic_close_list_2(conn, name):
 
         plus = '''
             <a href="/topic/''' + url_pas(name) + '?tool=close">(' + load_lang('closed_discussion') + ')</a> <a href="/topic/' + url_pas(name) + '?tool=agree">(' + load_lang('agreed_discussion') + ''')</a>
-            <hr class=\"main_hr\">
+            <hr class="main_hr">
             <form style="''' + display + '" method="post" action="/thread/' + topic_num + '''">
                 <input placeholder="''' + load_lang('discussion_name') + '''" name="title">
-                <hr class=\"main_hr\">
+                <hr class="main_hr">
                 <textarea rows="10" id="content" placeholder="''' + load_lang('content') + '''" name="content"></textarea>
-                <hr class=\"main_hr\">
+                <hr class="main_hr">
                 ''' + captcha_get() + (ip_warring() if display == '' else '') + '''
                 <input style="display: none;" name="topic" value="''' + name + '''">
                 <button type="submit">''' + load_lang('send') + '''</button>
                 <button id="preview" type="button" onclick="load_preview(\'''' + url_pas(name) + '\')">' + load_lang('preview') + '''</button>
             </form>
-            <hr class=\"main_hr\">
+            <hr class="main_hr">
             <div id="see_preview"></div>
         '''
 
         curs.execute(db_change("select code, sub from rd where title = ? and stop != 'O' order by date desc"), [name])
 
-    t_num = 0
     for data in curs.fetchall():
-        t_num += 1
-        t_str_num = str(t_num)
-
-        curs.execute(db_change("select id from topic where code = ? order by date desc limit 1"), [data[0]])
+        curs.execute(db_change("select id from topic where code = ? order by id + 0 desc limit 1"), [data[0]])
         t_data = curs.fetchall()
 
         div += '''
-            <h2><a href="/thread/''' + data[0] + '">' + t_str_num + '. ' + data[1] + '''</a></h2>
-            <div id="topic_pre_''' + t_str_num + '''"></div>
-            <div id="topic_back_pre_''' + t_str_num + '''"></div>
+            <h2><a href="/thread/''' + data[0] + '">' + data[0] + '. ' + data[1] + '''</a></h2>
+            <div id="topic_pre_''' + data[0] + '''"></div>
+            <div id="topic_back_pre_''' + data[0] + '''"></div>
             <script>
-                topic_list_load(''' + data[0] + ', 1, "topic_pre_' + t_str_num + '''");
+                new_topic_load(''' + data[0] + ', "list", "?num=1", "topic_pre_' + data[0] + '''");
                 if(''' + t_data[0][0] + ''' !== 1) {
-                    topic_list_load(''' + data[0] + ', ' + t_data[0][0] + ', "topic_back_pre_' + t_str_num + '''");
+                    new_topic_load(''' + data[0] + ', "list", "?num=' + t_data[0][0] + '", "topic_back_pre_' + data[0] + '''");
                 }
             </script>
         '''

+ 3 - 3
route/topic_tool.py

@@ -24,14 +24,14 @@ def topic_tool_2(conn, topic_num):
     if admin_check(3) == 1:
         data = '''
             <h2>''' + load_lang('admin_tool') + '''</h2>
-            <ul>
+            <ul class="inside_ul">
                 <li><a href="/thread/''' + topic_num + '/setting">' + load_lang('topic_setting') + '''</a></li>
                 <li><a href="/thread/''' + topic_num + '/acl">' + load_lang('topic_acl_setting') + '''</a></li>
             </ul>
         '''
     data += '''
         <h2>''' + load_lang('tool') + '''</h2>
-        <ul>
+        <ul class="inside_ul">
             <li>''' + load_lang('topic_state') + ''' : ''' + t_state + '' + (' (Agree)' if close_data and (close_data[0][1] == 'O') else '') + '''</li>
             <li>''' + load_lang('topic_acl') + ''' : <a href="/acl/TEST#exp">''' + ('Normal' if not topic_acl_get or (topic_acl_get[0][0] == '') else topic_acl_get[0][0]) + '''</a></li>
         </ul>
@@ -40,7 +40,7 @@ def topic_tool_2(conn, topic_num):
     if admin_check(None) == 1:
         data += '''
             <h2>''' + load_lang('owner') + '''</h2>
-            <ul>
+            <ul class="inside_ul">
                 <li>
                     <a href="/thread/''' + topic_num + '''/delete">
                         ''' + load_lang('topic_delete') + '''

+ 1 - 1
route/user_count_edit.py

@@ -25,7 +25,7 @@ def user_count_edit_2(conn, name):
     return easy_minify(flask.render_template(skin_check(),
         imp = [load_lang('count'), wiki_set(), custom(), other2([0, 0])],
         data = '''
-            <ul>
+            <ul class="inside_ul">
                 <li><a href="/record/''' + url_pas(that) + '''">''' + load_lang('edit_record') + '''</a> : ''' + str(data) + '''</li>
                 <li><a href="/topic_record/''' + url_pas(that) + '''">''' + load_lang('discussion_record') + '''</a> : ''' + str(t_data) + '''</a></li>
             </ul>

+ 26 - 23
route/user_custom_head_view.py

@@ -8,11 +8,11 @@ def user_custom_head_view_2(conn):
     if flask.request.method == 'POST':
         get_data = flask.request.form.get('content', '')
         if ip_or_user(ip) == 0:
-            curs.execute(db_change("select user from custom where user = ?"), [ip + ' (head)'])
+            curs.execute(db_change("select id from user_set where id = ? and name = 'custom_css'"), [ip])
             if curs.fetchall():
-                curs.execute(db_change("update custom set css = ? where user = ?"), [get_data, ip + ' (head)'])
+                curs.execute(db_change("update user_set set data = ? where id = ? and name = 'custom_css'"), [get_data, ip])
             else:
-                curs.execute(db_change("insert into custom (user, css) values (?, ?)"), [ip + ' (head)', get_data])
+                curs.execute(db_change("insert into user_set (id, name, data) values (?, 'custom_css', ?)"), [ip, get_data])
 
             conn.commit()
 
@@ -23,30 +23,33 @@ def user_custom_head_view_2(conn):
         if ip_or_user(ip) == 0:
             start = ''
 
-            curs.execute(db_change("select css from custom where user = ?"), [ip + ' (head)'])
+            curs.execute(db_change("select data from user_set where id = ? and name = 'custom_css'"), [ip])
             head_data = curs.fetchall()
-            if head_data:
-                data = head_data[0][0]
-            else:
-                data = ''
+            data = head_data[0][0] if head_data else ''
         else:
-            start = '<span>' + load_lang('user_head_warring') + '</span><hr class=\"main_hr\">'
-
-            if 'head' in flask.session:
-                data = flask.session['head']
-            else:
-                data = ''
-
-        start += '<span>&lt;style&gt;CSS&lt;/style&gt;<br>&lt;script&gt;JS&lt;/script&gt;</span><hr class=\"main_hr\">'
+            start = '' + \
+                '<span>' + load_lang('user_head_warring') + '</span>' + \
+                '<hr class="main_hr">' + \
+            ''
+            data = flask.session['head'] if 'head' in flask.session else ''
+
+        start += '' + \
+            '<span>' + \
+                '&lt;style&gt;CSS&lt;/style&gt;' + \
+                '<br>' + \
+                '&lt;script&gt;JS&lt;/script&gt;' + \
+            '</span>' + \
+            '<hr class="main_hr">' + \
+        ''
 
         return easy_minify(flask.render_template(skin_check(),
             imp = [load_lang(data = 'user_head', safe = 1), wiki_set(), custom(), other2([0, 0])],
-            data =  start + '''
-                    <form method="post">
-                        <textarea rows="25" cols="100" name="content">''' + data + '''</textarea>
-                        <hr class=\"main_hr\">
-                        <button id="save" type="submit">''' + load_lang('save') + '''</button>
-                    </form>
-                    ''',
+            data = start + '''
+                <form method="post">
+                    <textarea rows="25" cols="100" name="content">''' + data + '''</textarea>
+                    <hr class="main_hr">
+                    <button id="save" type="submit">''' + load_lang('save') + '''</button>
+                </form>
+            ''',
             menu = [['user', load_lang('return')]]
         ))

+ 4 - 3
route/user_info.py

@@ -25,6 +25,7 @@ def user_info_2(conn):
         plus = '''
             <li><a href="/login">''' + load_lang('login') + '''</a></li>
             <li><a href="/register">''' + load_lang('register') + '''</a></li>
+            <li><a href="/change">''' + load_lang('user_setting') + '''</a></li>
         '''
         plus3 = ''
 
@@ -41,18 +42,18 @@ def user_info_2(conn):
             <script>load_user_info("''' + ip + '''");</script>
             <br>
             <h2>''' + load_lang('login') + '''</h2>
-            <ul>
+            <ul class="inside_ul">
                 ''' + plus + '''
             </ul>
             <br>
             <h2>''' + load_lang('tool') + '''</h2>
-            <ul>
+            <ul class="inside_ul">
                 ''' + plus3 + '''
                 <li><a href="/custom_head">''' + load_lang('user_head') + '''</a></li>
             </ul>
             <br>
             <h2>''' + load_lang('other') + '''</h2>
-            <ul>
+            <ul class="inside_ul">
             ''' + plus2 + '''
             <li>
                 <a href="/count">''' + load_lang('count') + '''</a>

+ 75 - 38
route/user_setting.py

@@ -11,30 +11,32 @@ def user_setting_2(conn, server_init):
 
     if ip_or_user(ip) == 0:
         if flask.request.method == 'POST':
-            pass_list = ['2fa']
-            auto_list = ['skin', 'lang'] + pass_list + ['2fa_pw', '2fa_pw_encode']
-
+            auto_list = [
+                ['skin', flask.request.form.get('skin', '')], 
+                ['lang', flask.request.form.get('lang', '')]
+            ]
+                
+            twofa_turn_on = 0 
+            twofa_on = flask.request.form.get('2fa', '')
+            if twofa_on != '':
+                twofa_turn_on = 1
+                twofa_pw = flask.request.form.get('2fa_pw', '')
+                if twofa_pw != '':
+                    twofa_pw = pw_encode(twofa_pw)
+                    curs.execute(db_change("select encode from user where id = ?"), [ip])
+                    twofa_encode = curs.fetchall()[0][0]
+                    auto_list += [['2fa', 'on'], ['2fa_pw', twofa_pw], ['2fa_pw_encode', twofa_encode]]
+                else:
+                    auto_list += [['2fa', 'on']]
+            else:
+                auto_list += [['2fa', '']]
+                
             for auto_data in auto_list:
-                if auto_data == '2fa_pw':
-                    if flask.request.form.get('2fa_pw', '') != '':
-                        get_data = pw_encode(flask.request.form.get(auto_data, ''))
-                    else:
-                        get_data = ''
-                elif auto_data == '2fa_pw_encode':
-                    if flask.request.form.get('2fa_pw', '') != '':
-                        curs.execute(db_change("select encode from user where id = ?"), [ip])
-                        get_data = curs.fetchall()[0][0]
-                    else:
-                        get_data = ''
+                curs.execute(db_change('select data from user_set where name = ? and id = ?'), [auto_data[0], ip])
+                if curs.fetchall():
+                    curs.execute(db_change("update user_set set data = ? where name = ? and id = ?"), [auto_data[1], auto_data[0], ip])
                 else:
-                    get_data = flask.request.form.get(auto_data, '')
-
-                if auto_data in pass_list or get_data != '':
-                    curs.execute(db_change('select data from user_set where name = ? and id = ?'), [auto_data, ip])
-                    if curs.fetchall():
-                        curs.execute(db_change("update user_set set data = ? where name = ? and id = ?"), [get_data, auto_data, ip])
-                    else:
-                        curs.execute(db_change("insert into user_set (name, id, data) values (?, ?, ?)"), [auto_data, ip, get_data])
+                    curs.execute(db_change("insert into user_set (name, id, data) values (?, ?, ?)"), [auto_data[0], ip, auto_data[1]])
 
             conn.commit()
 
@@ -42,18 +44,14 @@ def user_setting_2(conn, server_init):
         else:
             curs.execute(db_change('select data from user_set where name = "email" and id = ?'), [ip])
             data = curs.fetchall()
-            if data:
-                email = data[0][0]
-            else:
-                email = '-'
+            email = data[0][0] if data else '-'
 
             div2 = load_skin('', 0, 1)
             div3 = ''
 
             curs.execute(db_change('select data from user_set where name = "lang" and id = ?'), [ip_check()])
             data = curs.fetchall()
-            if not data:
-                data = [['default']]
+            data = [['default']] if not data else data
 
             for lang_data in support_language:
                 see_data = lang_data if lang_data != 'default' else load_lang('default')
@@ -70,11 +68,6 @@ def user_setting_2(conn, server_init):
             curs.execute(db_change('select data from user_set where name = "2fa_pw" and id = ?'), [ip])
             fa_data_pw = curs.fetchall()
             fa_data_pw = load_lang('2fa_password_change') if fa_data_pw else load_lang('2fa_password')
-            
-            http_warring = '' + \
-                '<hr class="main_hr">' + \
-                '<span>' + load_lang('http_warring') + '</span>' + \
-            ''
 
             return easy_minify(flask.render_template(skin_check(),
                 imp = [load_lang('user_setting'), wiki_set(), custom(), other2([0, 0])],
@@ -94,15 +87,59 @@ def user_setting_2(conn, server_init):
                         <hr class="main_hr">
                         <select name="lang">''' + div3 + '''</select>
                         <h2>''' + load_lang('2fa') + '''</h2>
-                        <input type="checkbox" name="2fa" value="on" ''' + fa_data + '''> ''' + load_lang('on') + '''
-                        <hr class="main_hr">
-                        <input type="password" name="2fa_pw" placeholder="''' + fa_data_pw + '''">
+                        <input type="checkbox" id="twofa_check_input" onclick="do_twofa_check(0);" name="2fa" value="on" ''' + fa_data + '''> ''' + load_lang('on') + '''
+                        <div id="fa_plus_content">
+                            <hr class="main_hr">
+                            <input type="password" name="2fa_pw" placeholder="''' + fa_data_pw + '''">
+                        </div>
                         <hr class="main_hr">
                         <button type="submit">''' + load_lang('save') + '''</button>
-                        ''' + http_warring + '''
+                        ''' + http_warring() + '''
+                        <script>do_twofa_check(1);</script>
                     </form>
                 ''',
                 menu = [['user', load_lang('return')]]
             ))
     else:
-        return redirect('/login')
+        if flask.request.method == 'POST':
+            flask.session['skin'] = flask.request.form.get('skin', '')
+            flask.session['lang'] = flask.request.form.get('lang', '')
+            
+            return redirect('/change')
+        else:
+            div2 = load_skin(('' if not 'skin' in flask.session else flask.session['skin']), 0, 1)
+            div3 = ''
+
+            data = [['default']] if not 'lang' in flask.session else [[flask.session['lang']]]
+
+            for lang_data in support_language:
+                see_data = lang_data if lang_data != 'default' else load_lang('default')
+                
+                if data and data[0][0] == lang_data:
+                    div3 = '<option value="' + lang_data + '">' + see_data + '</option>' + div3
+                else:
+                    div3 += '<option value="' + lang_data + '">' + see_data + '</option>'
+            
+            return easy_minify(flask.render_template(skin_check(),
+                imp = [load_lang('user_setting'), wiki_set(), custom(), other2([0, 0])],
+                data = '''
+                    <form method="post">
+                        <span>''' + load_lang('id') + ''' : ''' + ip_pas(ip) + '''</span>
+                        <hr class="main_hr">
+                        <h2>''' + load_lang('main') + '''</h2>
+                        <span>''' + load_lang('skin') + '''</span>
+                        <hr class="main_hr">
+                        <select name="skin">''' + div2 + '''</select>
+                        <hr class="main_hr">
+                        <span>''' + load_lang('language') + '''</span>
+                        <hr class="main_hr">
+                        <select name="lang">''' + div3 + '''</select>
+                        <hr class="main_hr">
+                        <button type="submit">''' + load_lang('save') + '''</button>
+                        ''' + http_warring() + '''
+                        <hr class="main_hr">
+                        <span>''' + load_lang('user_head_warring') + '''</span>
+                    </form>
+                ''',
+                menu = [['user', load_lang('return')]]
+            ))

+ 4 - 7
route/user_tool.py

@@ -5,7 +5,7 @@ def user_tool_2(conn, name):
 
     data = '''
         <h2>''' + load_lang('tool') + '''</h2>
-        <ul>
+        <ul class="inside_ul">
             <li><a href="/record/''' + url_pas(name) + '''">''' + load_lang('record') + '''</a></li>
             <li><a href="/topic/user:''' + url_pas(name) + '''">''' + load_lang('user_discussion') + '''</a></li>
         </ul>
@@ -13,14 +13,11 @@ def user_tool_2(conn, name):
 
     if admin_check(1) == 1:
         curs.execute(db_change("select block from rb where block = ? and ongoing = '1'"), [name])
-        if curs.fetchall():
-            ban_name = load_lang('release')
-        else:
-            ban_name = load_lang('ban')
-
+        ban_name = load_lang('release') if curs.fetchall() else load_lang('ban')
+        
         data += '''
             <h2>''' + load_lang('admin') + '''</h2>
-            <ul>
+            <ul class="inside_ul">
                 <li><a href="/ban/''' + url_pas(name) + '''">''' + ban_name + '''</a></li>
                 <li><a href="/check/''' + url_pas(name) + '''">''' + load_lang('check') + '''</a></li>
             </ul>

+ 40 - 46
route/view_diff_data.py

@@ -15,50 +15,44 @@ def view_diff_data_2(conn, name):
 
     curs.execute(db_change("select data from history where id = ? and title = ?"), [first, name])
     first_raw_data = curs.fetchall()
-    if first_raw_data:
+        
+    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', '')
-
-        curs.execute(db_change("select data from history where id = ? and title = ?"), [second, name])
-        second_raw_data = curs.fetchall()
-        if second_raw_data:
-            second_raw_data = second_raw_data[0][0].replace('\r', '')
-
-            if first == second:
-                result = ''
-            elif first_raw_data == second_raw_data:
-                result = ''
-            else:
-                i = 1
-                include_ins = 0
-                diff_data = diff_match_patch().diff_prettyHtml(diff_match_patch().diff_main(first_raw_data, second_raw_data))
-                end_data = ''
-
-                re_data = re.findall(r'(?:(?:(?:(?!&para;<br>).)*)(?:&para;<br>)|(?:(?:(?!&para;<br>).)+)$)', diff_data)
-                for re_in_data in re_data:
-                    re_in_data = re.sub(r'&para;<br>$', '', re_in_data)
-                    if re.search(r'<ins (((?!<\/ins>).)+)<\/ins>', re_in_data):
-                        end_data += str(i) + ' : ' + re_in_data + '\n'
-                        include_ins = 0
-                    elif re.search(r'(<ins |<del )', re_in_data) and re.search(r'(<\/ins>|<\/del>)', re_in_data):
-                        end_data += str(i) + ' : ' + re_in_data + '\n'
-                        include_ins = 1
-                    elif re.search(r'(<\/ins>|<\/del>)', re_in_data):
-                        end_data += str(i) + ' : ' + re_in_data + '\n'
-                        include_ins = 0
-                    elif re.search(r'(<ins |<del )', re_in_data) or include_ins == 1:
-                        end_data += str(i) + ' : ' + re_in_data + '\n'
-                        include_ins = 1
-                    else:
-                        include_ins = 0
-
-                    i += 1
-                    
-                result = '<pre>' + end_data + '</pre>'
-
-            return easy_minify(flask.render_template(skin_check(),
-                imp = [name, wiki_set(), custom(), other2(['(' + load_lang('compare') + ')', 0])],
-                data = result,
-                menu = [['history/' + url_pas(name), load_lang('return')]]
-            ))
-
-    return redirect('/history/' + url_pas(name))
+        second_raw_data = second_raw_data[0][0].replace('\r', '')
+
+        if first_raw_data == second_raw_data:
+            result = ''
+        else:
+            i = 1
+            change_count = 0
+            diff_data = diff_match_patch().diff_prettyHtml(
+                diff_match_patch().diff_main(first_raw_data, second_raw_data)
+            )
+            end_data = ''
+
+            diff_data = diff_data.replace('&para;<br>', '\n')
+            diff_data = diff_data.replace('<span>', '')
+            diff_data = diff_data.replace('</span>', '')
+            
+            re_data = re.findall(r'(?:(?:(?:(?!\n).)*)(?:\n)|(?:(?:(?!\n).)+)$)', diff_data)
+            for re_in_data in re_data:
+                change_find_start = len(re.findall(r'<(?:del|ins) ', re_in_data))
+                change_find_end = len(re.findall(r'<\/(?:del|ins)>', re_in_data))
+
+                change_count += (change_find_start - change_find_end)
+                if change_count != 0 or change_find_start != 0 or change_find_end != 0:
+                    end_data += str(i) + ' : ' + re_in_data
+                
+                i += 1
+                
+            result = '<pre>' + end_data + '</pre>'
+
+        return easy_minify(flask.render_template(skin_check(),
+            imp = [name, wiki_set(), custom(), other2(['(' + load_lang('compare') + ')', 0])],
+            data = result,
+            menu = [['history/' + url_pas(name), load_lang('return')]]
+        ))
+    else:
+        return redirect('/history/' + url_pas(name))

+ 1 - 1
route/view_down.py

@@ -3,7 +3,7 @@ from .tool.func import *
 def view_down_2(conn, name):
     curs = conn.cursor()
 
-    div = '<ul>'
+    div = '<ul class="inside_ul">'
 
     curs.execute(db_change("select title from data where title like ?"), [name + '/%'])
     for data in curs.fetchall():

+ 18 - 24
route/view_read.py

@@ -9,28 +9,18 @@ def view_read_2(conn, name):
     run_redirect = ''
 
     num = flask.request.args.get('num', None)
-    if num:
-        num = int(number_check(num))
+    num = int(number_check(num)) if num else None
 
     curs.execute(db_change("select sub from rd where title = ? and not stop = 'O' order by date desc"), [name])
-    if curs.fetchall():
-        topic = 1
-    else:
-        topic = 0
+    topic = 1 if curs.fetchall() else 0
 
     curs.execute(db_change("select link from back where title = ? and type = 'cat' order by link asc"), [name])
 
     curs.execute(db_change("select title from data where title like ?"), ['%' + name + '/%'])
-    if curs.fetchall():
-        down = 1
-    else:
-        down = 0
+    down = 1 if curs.fetchall() else 0
 
     m = re.search(r"^(.*)\/(.*)$", name)
-    if m:
-        uppage = m.group(1)
-    else:
-        uppage = 0
+    uppage = m.group(1) if m else 0
 
     if re.search(r'^category:', name):
         curs.execute(db_change("select link from back where title = ? and type = 'cat' order by link asc"), [name])
@@ -40,7 +30,7 @@ def view_read_2(conn, name):
 
             for data in back:
                 if div == '':
-                    div = '<br><h2 id="cate_normal">' + load_lang('category_title') + '</h2><ul>'
+                    div = '<br><h2 id="cate_normal">' + load_lang('category_title') + '</h2><ul class="inside_ul">'
 
                 if re.search(r'^category:', data[0]):
                     u_div += '<li><a href="/w/' + url_pas(data[0]) + '">' + data[0] + '</a></li>'
@@ -56,7 +46,7 @@ def view_read_2(conn, name):
                 div += '</ul>'
 
             if u_div != '':
-                div += '<br><h2 id="cate_under">' + load_lang('under_category') + '</h2><ul>' + u_div + '</ul>'
+                div += '<br><h2 id="cate_under">' + load_lang('under_category') + '</h2><ul class="inside_ul">' + u_div + '</ul>'
 
 
     cache_data = None
@@ -106,26 +96,26 @@ def view_read_2(conn, name):
         curs.execute(db_change('select data from other where name = "error_401"'))
         sql_d = curs.fetchall()
         if sql_d and sql_d[0][0] != '':
-            end_data = '<h2>' + load_lang('error') + '</h2><ul><li>' + sql_d[0][0] + '</li></ul>'
+            end_data = '<h2>' + load_lang('error') + '</h2><ul class="inside_ul"><li>' + sql_d[0][0] + '</li></ul>'
         else:
-            end_data = '<h2>' + load_lang('error') + '</h2><ul><li>' + load_lang('authority_error') + '</li></ul>'
+            end_data = '<h2>' + load_lang('error') + '</h2><ul class="inside_ul"><li>' + load_lang('authority_error') + '</li></ul>'
     elif end_data == 'HTTP Request 404':
         response_data = 404
 
         curs.execute(db_change('select data from other where name = "error_404"'))
         sql_d = curs.fetchall()
         if sql_d and sql_d[0][0] != '':
-            end_data = '<h2>' + load_lang('error') + '</h2><ul><li>' + sql_d[0][0] + '</li></ul>'
+            end_data = '<h2>' + load_lang('error') + '</h2><ul class="inside_ul"><li>' + sql_d[0][0] + '</li></ul>'
         else:
-            end_data = '<h2>' + load_lang('error') + '</h2><ul><li>' + load_lang('decument_404_error') + '</li></ul>'
+            end_data = '<h2>' + load_lang('error') + '</h2><ul class="inside_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" and type = "" order by id + 0 desc limit 3' + \
+            '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>'
+            end_data += '<h2>' + load_lang('history') + '</h2><ul class="inside_ul">'
             for i in sql_d:
                 if re.search(r"\+", i[2]):
                     leng = '<span style="color:green;">(' + i[2] + ')</span>'
@@ -146,10 +136,14 @@ def view_read_2(conn, name):
         acl = 0
         r_date = 0
     else:
-        curs.execute(db_change("select decu from acl where title = ?"), [name])
+        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 = [['edit/' + url_pas(name), load_lang('create'), menu_acl]] if response_data == 404 else [['edit/' + url_pas(name), load_lang('edit'), menu_acl]]
+        if response_data == 404:
+            menu = [['edit/' + url_pas(name), load_lang('create'), menu_acl]] 
+        else:
+            menu = [['edit/' + url_pas(name), load_lang('edit'), menu_acl]]
+            
         menu += [
             ['topic/' + url_pas(name), load_lang('discussion'), topic], 
             ['history/' + url_pas(name), load_lang('history')], 

+ 1 - 1
route/view_xref.py

@@ -17,7 +17,7 @@ def view_xref_2(conn, name):
     else:
         div = '<a href="?change=1">(' + load_lang('normal') + ')</a><hr class="main_hr">'
 
-    div += '<ul>'
+    div += '<ul class="inside_ul">'
 
     if flask.request.args.get('change', '1') == '1':
         curs.execute(db_change("" + \

+ 1 - 1
route/vote.py

@@ -16,7 +16,7 @@ def vote_2(conn):
         sub = '(' + load_lang('closed') + ')'
         curs.execute(db_change('select name, id, type from vote where type = "close" or type = "n_close" limit ?, 50'), [sql_num])
 
-    data += '<ul>'
+    data += '<ul class="inside_ul">'
 
     data_list = curs.fetchall()
     for i in data_list:

+ 1 - 1
route/vote_end.py

@@ -28,7 +28,7 @@ def vote_end_2(conn, num):
     vote_data = re.findall(r'([^\n]+)', data_list[0][2].replace('\r\n', '\n'))
     for i in range(0, len(vote_data)):
         data += '<h2>' + vote_data[i] + '</h2>'
-        data += '<ul>'
+        data += '<ul class="inside_ul">'
         
         curs.execute(db_change('select user from vote where id = ? and user != "" and data = ?'), [num, str(i)])
         data_list_2 = curs.fetchall()

+ 1 - 1
route/watch_list.py

@@ -47,7 +47,7 @@ def watch_list_2(conn, tool):
         ''
 
     if data:
-        div = '<ul>' + div + '</ul><hr class=\"main_hr\">'
+        div = '<ul class="inside_ul">' + div + '</ul><hr class=\"main_hr\">'
 
     div += '<a href="/manager/' + ('13' if tool == 'watch_list' else '16') + '">(' + load_lang('add') + ')</a>'
 

+ 3 - 3
version.json

@@ -1,7 +1,7 @@
 {
     "beta" : {
-        "r_ver" : "v3.2.0-stable-12 (beta-31) (dev-2020-09-04-01)",
-        "c_ver" : "3202600",
-        "s_ver" : "10"
+        "r_ver" : "v3.2.0-stable-13 (beta-60) (dev-2021-03-29-01)",
+        "c_ver" : "3206000",
+        "s_ver" : "11"
     }
 }

+ 249 - 53
views/main_css/css/main.css

@@ -1,53 +1,249 @@
-body, html, video, table, div, iframe, input, textarea, img, hr, blockquote, pre { max-width: 100%;}
-textarea { width: 100%; }
-input { width: 100%; box-sizing: border-box; }
-#last { margin-top: 30px; }
-#toc { border: 1px solid; padding: 20px; width: fit-content; width: -moz-fit-content; clear: both; margin-top: 10px; }
-#toc-name { font-size: 18px; }
-table { border-collapse: collapse; }
-td { border: 1px solid; padding: 5px; }
-a { text-decoration: none; }
-#not_thing { color: red; }
-#inside, #out_link, #open { color: green; }
-#out_link::before { background: green; color: white; content: "E"; }
-input[type="checkbox"], input[type="radio"] { width: auto; }
-#list { padding: 10px; }
-#toron { width: 100%; }
-#toron_color_green { background: #99ffcd; }
-#toron_color_blue { background: #ffcbf9; }
-#toron_color_red { background: #fecabf; }
-#toron_color_grey { background: gainsboro; }
-#toron_color_not { display: none; }
-#cate { border: 1px solid; padding: 5px; margin-top: 20px; }
-blockquote { border: 1px solid; padding: 15px; margin: 0; margin-top: 10px; display: inline-block; }
-img, iframe { max-width: 100%; }
-pre { border: 1px solid; padding: 10px; white-space: pre-wrap; }
-#in { margin-left: 20px; }
-#out { margin-left: 5px; }
-s, strike, del { color: gray; }
-s:hover, strike:hover, del:hover { color: gray; background-color: gainsboro; text-decoration: none; }
-#main_table_set { width: 100%; text-align: center; }
-#main_table_width { width: 33.3%; }
-#main_table_width_half { width: 50%; }
-#main_table_width_quarter { width: 25%; }
-#redirect { border: 1px solid; padding: 10px; }
-body { word-break: break-all; overflow: auto; }
-.main_hr { border: none; margin-top: 8px; margin-bottom: 8px; }
-#include_link { display: none; }
-#toc_title { font-size: 18px; }
-blockquote { background-image: url(/views/main_css/file/quote.png); background-position: calc(100% - 10px) 10px; background-repeat: no-repeat; background-size: 25px; }
-#admin_log_search { width: 100px; }
-@media (max-width: 768px) { table { min-width: 100%; } .table_safe { min-width: 100%; }}
-#origin { display: none; }
-.all_in_data { display: block; width: 100%; white-space: pre-wrap; }
-.table_safe { max-width: 100%; }
-.change_space { white-space: pre-line; }
-#topic_scroll { max-height: 500px; overflow: scroll; -ms-overflow-style: none; scrollbar-width: none; }
-#topic_scroll::-webkit-scrollbar { display: none; }
-.hidden_link { filter: blur(3px); }
-.hidden_link:hover { filter: none; }
-.content { height: 500px; }
-.topic_content { height: 200px; }
-.spead_footnote { background-color: #efefef; color: #555; border: 1px solid #cecece; }
-#footnote_data { border-top: 1px solid gainsboro; padding-top: 10px; }
-a { color: dodgerblue; }
+body, html, video, table, div, iframe, input, textarea, img, hr, blockquote, pre {
+    max-width: 100%;
+}
+
+textarea {
+    width: 100%;
+}
+
+input {
+    width: 100%;
+    box-sizing: border-box;
+}
+
+#last {
+    margin-top: 30px;
+}
+
+#toc {
+    border: 1px solid;
+    padding: 20px;
+    width: fit-content;
+    width: -moz-fit-content;
+    clear: both;
+    margin-top: 10px;
+}
+
+table {
+    border-collapse: collapse;
+}
+
+td {
+    border: 1px solid;
+    padding: 5px;
+}
+
+a {
+    text-decoration: none;
+}
+
+.inside_ul li {
+    margin-left: 20px;
+}
+
+#not_thing {
+    color: red;
+}
+
+#inside, #out_link, #open {
+    color: green;
+}
+
+#out_link::before {
+    background: green;
+    color: white;
+    content: "E";
+    margin-right: 2px;
+}
+
+input[type="checkbox"], input[type="radio"] {
+    width: auto;
+}
+
+#list {
+    padding: 10px;
+}
+
+#toron {
+    width: 100%;
+}
+
+#toron_color_green {
+    background: #99ffcd;
+}
+
+#toron_color_blue {
+    background: #ffcbf9;
+}
+
+#toron_color_red {
+    background: #fecabf;
+}
+
+#toron_color_grey {
+    background: gainsboro;
+}
+
+#toron_color_not {
+    display: none;
+}
+
+#cate {
+    border: 1px solid;
+    padding: 5px;
+    margin-top: 20px;
+}
+
+img, iframe {
+    max-width: 100%;
+}
+
+pre {
+    border: 1px solid;
+    padding: 10px;
+    white-space: pre-wrap;
+}
+
+#in {
+    margin-left: 20px;
+}
+
+#out {
+    margin-left: 5px;
+}
+
+s, strike, del {
+    color: gray;
+}
+
+s:hover, strike:hover, del:hover {
+    color: gray;
+    background-color: gainsboro;
+    text-decoration: none;
+}
+
+#main_table_set {
+    width: 100%;
+    text-align: center;
+}
+
+#main_table_width {
+    width: 33.3%;
+}
+
+#main_table_width_half {
+    width: 50%;
+}
+
+#main_table_width_quarter {
+    width: 25%;
+}
+
+#redirect {
+    border: 1px solid;
+    padding: 10px;
+}
+
+body {
+    word-break: break-all;
+    overflow: auto;
+}
+
+.main_hr {
+    border: none;
+    margin-top: 8px;
+    margin-bottom: 8px;
+}
+
+#include_link {
+    display: none;
+}
+
+#toc_title {
+    font-size: 1.2rem;
+}
+
+#admin_log_search {
+    width: 100px;
+}
+
+@media (max-width: 768px) {
+    table {
+        min-width: 100%;
+    }
+    .table_safe {
+        min-width: 100%;
+    }
+}
+
+.all_in_data {
+    display: block;
+    width: 100%;
+    white-space: pre-wrap;
+}
+
+.table_safe {
+    max-width: 100%;
+}
+
+.change_space {
+    white-space: pre-line;
+}
+
+#topic_scroll {
+    max-height: 500px;
+    overflow: scroll;
+    -ms-overflow-style: none;
+    scrollbar-width: none;
+}
+
+#topic_scroll::-webkit-scrollbar {
+    display: none;
+}
+
+.hidden_link {
+    filter: blur(3px);
+}
+
+.hidden_link:hover {
+    filter: none;
+}
+
+.content {
+    height: 500px;
+}
+
+.topic_content {
+    height: 200px;
+}
+
+.spead_footnote {
+    background-color: #efefef;
+    color: #555;
+    border: 1px solid #cecece;
+}
+
+#footnote_data {
+    border-top: 1px solid gainsboro;
+    padding-top: 10px;
+}
+
+a {
+    color: dodgerblue;
+}
+
+blockquote {
+    padding: 15px 40px 15px 15px;
+    margin: 15px 0 0;
+    display: table;
+    border: 2px solid #ccc;
+    border-left: 5px solid black;
+    background-image: url('/views/main_css/file/quote.png');
+    background-position: calc(100% - 10px) 10px;
+    background-repeat: no-repeat;
+    background-size: 25px;
+}
+
+hr {
+    border-top: 1px solid lightgray;
+}

+ 51 - 12
views/main_css/css/sub/dark.css

@@ -1,12 +1,51 @@
-html { background: black; color: white; }
-textarea, input, button, select { background: #1f2023; color: white; }
-input::placeholder, textarea::placeholder, select::placeholder { color: white; }
-#toc, #cate, #redirect { background: #1f2023; }
-#toron_color_grey { background: #4a4a4a; }
-#toron_color_green { background: #2e4a2e; }
-#toron_color_red { background: #803737; }
-#toron_color_blue { background: #314c56; }
-pre#syntax, pre#syntax code { background: black; }
-.hljs, .hljs-subst { color: white; }
-blockquote { background-color: black; border-left: 5px solid #eee; }
-.spead_footnote { background-color: black; color: white; }
+html, body {
+    background: black;
+    color: white;
+}
+
+textarea, input, button, select {
+    background: #1f2023;
+    color: white;
+}
+
+input::placeholder, textarea::placeholder, select::placeholder {
+    color: white;
+}
+
+#toc, #cate, #redirect {
+    background: #1f2023;
+}
+
+#toron_color_grey {
+    background: #4a4a4a;
+}
+
+#toron_color_green {
+    background: #2e4a2e;
+}
+
+#toron_color_red {
+    background: #803737;
+}
+
+#toron_color_blue {
+    background: #314c56;
+}
+
+pre#syntax, pre#syntax code {
+    background: black;
+}
+
+.hljs, .hljs-subst {
+    color: white;
+}
+
+blockquote {
+    background-color: black;
+    border-left: 5px solid #eee;
+}
+
+.spead_footnote {
+    background-color: black;
+    color: white;
+}

+ 34 - 17
views/main_css/file/easter_egg.html

@@ -1,23 +1,40 @@
 <div id="easter_egg"></div>
 <script>
-    var random_num = String(Math.floor(Math.random() * 7));
-    var random_code = '';
-    
-    if(random_num === '6') {
-        random_code = 'DzjjcMNrTHU';
-    } else if(random_num === '5') {
-        random_code = 'xpg2Ag-xt_c';
-    } else if(random_num === '4') {
-        random_code = 'IKIoAlhQV-c';
-    } else if(random_num === '3') {
-        random_code = 'MLOvyLsYJvo';
-    } else if(random_num === '2') {
-        random_code = 'Fsppuynb440';
-    } else if(random_num === '1') {
-        random_code = 'DbTIoBK9Wvo';
+    var random_code = [
+        'DzjjcMNrTHU', // 상해홍차관
+        'xpg2Ag-xt_c', // 죽취비상
+        'IKIoAlhQV-c', // 유령악단
+        'MLOvyLsYJvo', // 플라워링 나이트
+        'Fsppuynb440', // 우상에 세계를 맡기고
+        'DbTIoBK9Wvo', // 고향별이 비치는 바다
+        'nytZOF0hp_c', // 오늘 밤은 표일한 에고이스트
+        'I9GiwMcg424', // 브와르 마법 도서관
+        '8NQSBvzjWZk', // 배드애플
+        'uiqEO6BK7BM', // 달까지 닿아라 불사의 연기
+        'np7BG71YTIY', // 라스트 리모드
+        '8gaqt1AOyck', // 쇄월
+        'EsnW_hyI-V8', // 디자이어 드라이브
+        'es9twrnfZ_Q', // 유심지의 유정천
+    ];
+    var get_num = location.search.replace(/[^0-9]+/g, '');
+    if(get_num !== '' && Number(get_num) < random_code.length) {
+        var random_num = Number(get_num);
     } else {
-        random_code = 'nytZOF0hp_c'
+        var random_num = Math.floor(Math.random() * random_code.length);
     }
+    var random_code_select = random_code[random_num];
 
-    document.getElementById('easter_egg').innerHTML = '<iframe style="width: 560px; height: 315px;" src="https://www.youtube.com/embed/' + random_code + '" allowfullscreen></iframe>';
+    var i = 0;
+    var add_link = '';
+    while(i < random_code.length) {
+        add_link += '<a href="?select=' + String(i) + '">(' + String(i) + ')</a> ';
+        i += 1;
+    }
+
+    document.getElementById('easter_egg').innerHTML = '' +
+        add_link +
+        '<hr class="main_hr">' +
+        '<iframe     style="width: 560px; height: 315px;" ' +
+                    'src="https://www.youtube.com/embed/' + random_code_select + '" allowfullscreen></iframe>' +
+        '';
 </script>

+ 52 - 14
views/main_css/js/do_editor.js → views/main_css/js/load_editor.js

@@ -16,9 +16,17 @@ function do_insert_data(name, data) {
     }
 }
 
+function monaco_to_content() {
+    try {
+        document.getElementById('content').innerHTML = window.editor.getValue();
+    } catch(e) {}
+}
+
 function do_not_out() {
     window.addEventListener('DOMContentLoaded', function() {
         window.onbeforeunload = function() {
+            monaco_to_content();
+            
             data = document.getElementById('content').value;
             origin = document.getElementById('origin').value;
             if(data !== origin) {
@@ -48,20 +56,21 @@ function do_paste_image() {
 
 function pasteListener(e) {
     // find file
-    if (e.clipboardData && e.clipboardData.items) {
+    if(e.clipboardData && e.clipboardData.items) {
         const items = e.clipboardData.items;
         let haveImageInClipboard = false;
         const formData = new FormData();
-        for (let i = 0; i < items.length; i++) {
-            if (items[i].type.indexOf("image") !== -1) {
+        for(let i = 0; i < items.length; i++) {
+            if(items[i].type.indexOf("image") !== -1) {
                 const file = items[i].getAsFile();
-                const customName = prompt("파일 이름을 설정해주세요. (확장자는 생략)");
+                const customName = prompt("파일 이름 (확장자 제외)");
                 
                 if (!customName) {
-                    return alert("취소되었습니다.");
+                    return alert("파일 이름 없음");
                 }
                 
-                const customFile = new File([file], customName + ".png", { type: file.type });
+                var file_name = customName + ".png";
+                const customFile = new File([file], file_name, { type: file.type });
                 formData.append("f_data[]", customFile);
                 haveImageInClipboard = true;
                 e.preventDefault();
@@ -69,7 +78,8 @@ function pasteListener(e) {
                 break;
             }
         }
-        if (!haveImageInClipboard) {
+
+        if(!haveImageInClipboard) {
             return;
         }
 
@@ -81,22 +91,50 @@ function pasteListener(e) {
             if (res.status === 200 || res.status === 201) {
                 const url = res.url;
                 alert(
-                    '클립보드의 이미지를 성공적으로 업로드했습니다. 아래 텍스트로 본문에 삽입할 수 있습니다. ' +
-                    '[[' + decodeURIComponent(url.replace(/.*\/w\/file/, "file")) + ']]'
+                    '업로드 완료 : ' +
+                    '[[파일:' + file_name + ']]'
                 );
             } else {
                 console.error("[ERROR] PasteUpload Fail :", res.statusText);
                 if(res.status === 400) {
-                    alert("클립보드의 이미지를 업로드하는데 실패했습니다. 파일 이름 중복일 수 있습니다.");
+                    alert("파일 이름 중복");
                 } else if(res.status === 401) {
-                    alert("클립보드의 이미지를 업로드하는데 실패했습니다. 권한 부족일 수 있습니다.");    
+                    alert("권한 부족");    
                 } else {
-                    alert("클립보드의 이미지를 업로드하는데 실패했습니다.");        
+                    alert("업로드 실패");        
                 }
             }
         }).catch((err) => {
-            console.error("[ERROR] PasteUpload Fail :", JSON.stringify(err), err);
-            alert("클립보드의 이미지를 업로드하는데 실패했습니다. 서버가 응답하지 않습니다.");
+            console.error("오류 내역 :", JSON.stringify(err), err);
+            alert("업로드 실패");
         });
     }
+}
+
+function load_preview(name) {
+    var s_data = new FormData();
+    s_data.append('data', document.getElementById('content').value);
+
+    var url = "/api/w/" + name;
+    var url_2 = "/api/markup";
+
+    var xhr = new XMLHttpRequest();
+    xhr.open("POST", url, true);
+    xhr.send(s_data);
+
+    var xhr_2 = new XMLHttpRequest();
+    xhr_2.open("GET", url_2, true);
+    xhr_2.send(null);
+
+    xhr.onreadystatechange = function() {
+        if(xhr.readyState === 4 && xhr.status === 200) {
+            var o_p_data = JSON.parse(xhr.responseText);
+            document.getElementById('see_preview').innerHTML = o_p_data['data'];
+            eval(o_p_data['js_data'])
+        }
+    }
+}
+
+function load_raw_preview(name_1, name_2) {
+    document.getElementById(name_2).innerHTML = document.getElementById(name_1).value;
 }

+ 0 - 27
views/main_css/js/load_preview.js

@@ -1,27 +0,0 @@
-function load_preview(name) {
-    var s_data = new FormData();
-    s_data.append('data', document.getElementById('content').value);
-
-    var url = "/api/w/" + name;
-    var url_2 = "/api/markup";
-
-    var xhr = new XMLHttpRequest();
-    xhr.open("POST", url, true);
-    xhr.send(s_data);
-
-    var xhr_2 = new XMLHttpRequest();
-    xhr_2.open("GET", url_2, true);
-    xhr_2.send(null);
-
-    xhr.onreadystatechange = function() {
-        if(xhr.readyState === 4 && xhr.status === 200) {
-            var o_p_data = JSON.parse(xhr.responseText);
-            document.getElementById('see_preview').innerHTML = o_p_data['data'];
-            eval(o_p_data['js_data'])
-        }
-    }
-}
-
-function load_raw_preview(name_1, name_2) {
-    document.getElementById(name_2).innerHTML = document.getElementById(name_1).value;
-}

+ 228 - 41
views/main_css/js/load_skin_set.js

@@ -3,7 +3,7 @@ function main_css_regex_data(data) {
 }
 
 function main_css_get_post() {    
-    var check = document.getElementById('strike');
+    var check = document.getElementById('main_css_strike');
     if(check.value === 'normal') {
         document.cookie = 'main_css_del_strike=0;';
     } else if(check.value === 'change') {
@@ -12,7 +12,7 @@ function main_css_get_post() {
         document.cookie = 'main_css_del_strike=2;';
     }
 
-    check = document.getElementById('bold');
+    check = document.getElementById('main_css_bold');
     if(check.value === 'normal') {
         document.cookie = 'main_css_del_bold=0;';
     } else if(check.value === 'change') {
@@ -21,41 +21,66 @@ function main_css_get_post() {
         document.cookie = 'main_css_del_bold=2;';
     }
 
-    check = document.getElementById('include');
+    check = document.getElementById('main_css_include');
     if(check.checked) {
         document.cookie = 'main_css_include_link=1;';
     } else {
         document.cookie = 'main_css_include_link=0;';
     }
 
-    check = document.getElementById('category');
+    check = document.getElementById('main_css_category');
     if(check.value === 'bottom') {
         document.cookie = 'main_css_category_set=0;';
     } else {
         document.cookie = 'main_css_category_set=1;';
     }
 
-    check = document.getElementById('footnote');
+    check = document.getElementById('main_css_footnote');
     if(check.value === 'spread') {
         document.cookie = 'main_css_footnote_set=1;';
     } else {
         document.cookie = 'main_css_footnote_set=0;';
     }
 
-    check = document.getElementById('image');
-    if(check.value === 'click') {
+    check = document.getElementById('main_css_image');
+    if(check.value === 'new_click') {
+        document.cookie = 'main_css_image_set=2;';
+    } else if(check.value === 'click') {
         document.cookie = 'main_css_image_set=1;';
     } else {
         document.cookie = 'main_css_image_set=0;';
     }
 
-    check = document.getElementById('image_paste');
+    check = document.getElementById('main_css_image_paste');
     if(check.checked) {
         document.cookie = 'main_css_image_paste=1;';
     } else {
         document.cookie = 'main_css_image_paste=0;';
     }
 
+    check = document.getElementById('main_css_toc');
+    if(check.value === 'on') {
+        document.cookie = 'main_css_toc_set=2;';
+    } else if(check.value === 'off') {
+        document.cookie = 'main_css_toc_set=1;';
+    } else {
+        document.cookie = 'main_css_toc_set=0;';
+    }
+
+    check = document.getElementById('main_css_font_size');
+    if(check.value.match(/^[0-9]+$/)) {
+        document.cookie = 'main_css_font_size=' + check.value + ';';
+    } else {
+        document.cookie = 'main_css_font_size=;';
+    }
+
+    check = document.getElementById('main_css_monaco');
+    if(check.checked) {
+        document.cookie = 'main_css_monaco=1;';
+    } else {
+        document.cookie = 'main_css_monaco=0;';
+    }
+
     history.go(0);
 }
 
@@ -97,9 +122,24 @@ function main_css_skin_load() {
             head_data.innerHTML += '<style>#cate { margin-top: 0px; margin-bottom: 20px; }</style>';
         }
     }
+
+    if(
+        document.cookie.match(main_css_regex_data('main_css_font_size')) &&
+        document.cookie.match(main_css_regex_data('main_css_font_size'))[1] !== ''
+    ) {
+        head_data.innerHTML += '<style>.all_in_data { font-size: ' + document.cookie.match(main_css_regex_data('main_css_font_size'))[1] + 'px; }</style>';
+    }
+
+    if(document.cookie.match(main_css_regex_data('main_css_toc_set'))) {
+        if(document.cookie.match(main_css_regex_data('main_css_toc_set'))[1] === '2') {
+            head_data.innerHTML += '<style>#auto_toc { display: none; }</style>';
+        } else if(document.cookie.match(main_css_regex_data('main_css_toc_set'))[1] === '1') {
+            head_data.innerHTML += '<style>#toc { display: none; }</style>';
+        }
+    }
 }
 
-function main_css_skin_set() {    
+function main_css_load_lang(name) {
     var set_language = {
         "en-US" : {
             "default" : "Default",
@@ -116,7 +156,20 @@ function main_css_skin_set() {
             "set_footnote" : "Set footnote",
             "renderer" : "Renderer",
             "spread" : "Spread",
-            "set_image" : "Set image"
+            "set_image" : "Set image",
+            "set_toc" : "Set TOC",
+            "click_load" : "Load on click",
+            "in_content" : "Only when TOC is in the document",
+            "all_off" : "Always off",
+            "set_font_size" : "Set font size",
+            "change_to_link" : "Change to link",
+            "font_size" : "font size",
+            "editor" : "Editor",
+            "main" : "Main",
+            "clipboard_upload" : "Clipboard upload",
+            "only_korean" : "Supported in korean only",
+            "except_ie" : "Not supported for Internet Explorer",
+            "use_monaco" : "Use monaco editor"
         }, "ko-KR" : {
             "default" : "기본값",
             "change_to_normal" : "일반 텍스트로 변경",
@@ -132,25 +185,48 @@ function main_css_skin_set() {
             "set_footnote" : "각주 설정",
             "renderer" : "렌더러",
             "spread" : "펼치기",
-            "set_image" : "이미지 설정"
+            "set_image" : "이미지 설정",
+            "set_toc" : "목차 설정",
+            "click_load" : "클릭시 불러오기",
+            "in_content" : "문서 안에 있을 때만",
+            "all_off" : "항상 끔",
+            "set_font_size" : "글자 크기 설정",
+            "change_to_link" : "링크로 변경",
+            "font_size" : "글자 크기",
+            "editor" : "편집기",
+            "main" : "메인",
+            "clipboard_upload" : "클립보드 파일 올리기",
+            "only_korean" : "한국어로만 지원됨",
+            "except_ie" : "인터넷 익스플로러에선 지원되지 않음",
+            "use_monaco" : "모나코 에디터 사용"
         }
     }
 
-    var language = document.cookie.match(main_css_regex_data('language'))[1];
+    var server_language = document.cookie.match(main_css_regex_data('language'))[1];
     var user_language = document.cookie.match(main_css_regex_data('user_language'))[1];
     if(user_language in set_language) {
         language = user_language;
+    } else {
+        if(server_language in set_language) {
+            language = server_language;
+        } else {
+            language = 'en-US';
+        }
     }
 
-    if(!language in set_language) {
-        language = "en-US";
+    if(name in set_language[language]) {
+        return set_language[language][name];
+    } else {
+        return name + ' (' + language + ')';
     }
+}
 
+function main_css_skin_set() {    
     var set_data = {};
     var strike_list = [
-        ['0', 'normal', set_language[language]['default']],
-        ['1', 'change', set_language[language]['change_to_normal']],
-        ['2', 'delete', set_language[language]['delete']]
+        ['0', 'normal', main_css_load_lang('default')],
+        ['1', 'change', main_css_load_lang('change_to_normal')],
+        ['2', 'delete', main_css_load_lang('delete')]
     ];
     set_data["strike"] = '';
     var i = 0;
@@ -168,9 +244,9 @@ function main_css_skin_set() {
     }
 
     var bold_list = [
-        ['0', 'normal', set_language[language]['default']],
-        ['1', 'change', set_language[language]['change_to_normal']],
-        ['2', 'delete', set_language[language]['delete']]
+        ['0', 'normal', main_css_load_lang('default')],
+        ['1', 'change', main_css_load_lang('change_to_normal')],
+        ['2', 'delete', main_css_load_lang('delete')]
     ];
     set_data["bold"] = '';
     i = 0;
@@ -206,8 +282,8 @@ function main_css_skin_set() {
     }
 
     var category_list = [
-        ['0', 'bottom', set_language[language]['bottom']],
-        ['1', 'top', set_language[language]['top']],
+        ['0', 'bottom', main_css_load_lang('bottom')],
+        ['1', 'top', main_css_load_lang('top')],
     ];
     set_data["category"] = '';
     i = 0;
@@ -225,8 +301,8 @@ function main_css_skin_set() {
     }
 
     var footnote_list = [
-        ['0', 'normal', set_language[language]['default']],
-        ['1', 'spread', set_language[language]['spread']]
+        ['0', 'normal', main_css_load_lang('default')],
+        ['1', 'spread', main_css_load_lang('spread')]
     ];
     set_data["footnote"] = '';
     i = 0;
@@ -244,8 +320,9 @@ function main_css_skin_set() {
     }
 
     var image_list = [
-        ['0', 'normal', set_language[language]['default']],
-        ['1', 'click', 'click (beta)']
+        ['0', 'normal', main_css_load_lang('default')],
+        ['1', 'click', main_css_load_lang('change_to_link')],
+        ['2', 'new_click', main_css_load_lang('click_load')]
     ];
     set_data["image"] = '';
     i = 0;
@@ -262,33 +339,143 @@ function main_css_skin_set() {
         i += 1;
     }
 
+    var toc_list = [
+        ['0', 'normal', main_css_load_lang('default')],
+        ['1', 'off', main_css_load_lang('all_off')],
+        ['2', 'on', main_css_load_lang('in_content')]
+    ];
+    set_data["toc"] = '';
+    i = 0;
+    while(toc_list[i]) {
+        if(
+            document.cookie.match(main_css_regex_data('main_css_toc_set')) && 
+            document.cookie.match(main_css_regex_data('main_css_toc_set'))[1] === toc_list[i][0]
+        ) {
+            set_data["toc"] = '<option value="' + toc_list[i][1] + '">' + toc_list[i][2] + '</option>' + set_data["toc"];
+        } else {
+            set_data["toc"] += '<option value="' + toc_list[i][1] + '">' + toc_list[i][2] + '</option>';
+        }
+
+        i += 1;
+    }
+
+    if(document.cookie.match(main_css_regex_data('main_css_font_size'))) {
+        set_data["font_size"] = document.cookie.match(main_css_regex_data('main_css_font_size'))[1];
+    } else {
+        set_data["font_size"] = '';
+    }
+
+    if(
+        document.cookie.match(main_css_regex_data('main_css_monaco')) &&
+        document.cookie.match(main_css_regex_data('main_css_monaco'))[1] === '1'
+    ) {
+        set_data["monaco"] = "checked";
+    } else {
+        set_data["monaco"] = "";
+    }
+
     document.getElementById("main_skin_set").innerHTML = ' \
-        <h2>1. ' + set_language[language]['renderer'] + '</h2> \
-        <h3>1.1. ' + set_language[language]['strike'] + '</h3> \
-        <select id="strike" name="strike"> \
+        <h2>1. ' + main_css_load_lang('renderer') + '</h2> \
+        <h3>1.1. ' + main_css_load_lang('strike') + '</h3> \
+        <select id="main_css_strike"> \
             ' + set_data["strike"] + ' \
         </select> \
-        <h3>1.2. ' + set_language[language]['bold'] + '</h3> \
-        <select id="bold" name="bold"> \
+        <h3>1.2. ' + main_css_load_lang('bold') + '</h3> \
+        <select id="main_css_bold"> \
             ' + set_data["bold"] + ' \
         </select> \
-        <h3>1.3. ' + set_language[language]['where_category'] + '</h3> \
-        <select id="category" name="category"> \
+        <h3>1.3. ' + main_css_load_lang('where_category') + '</h3> \
+        <select id="main_css_category"> \
             ' + set_data["category"] + ' \
         </select> \
-        <h3>1.4. ' + set_language[language]['set_footnote'] + '</h3> \
-        <select id="footnote" name="footnote"> \
+        <h3>1.4. ' + main_css_load_lang('set_footnote') + '</h3> \
+        <select id="main_css_footnote"> \
             ' + set_data["footnote"] + ' \
         </select> \
-        <h3>1.5. ' + set_language[language]['set_image'] + '</h3> \
-        <select id="image" name="image"> \
+        <h3>1.5. ' + main_css_load_lang('set_image') + '</h3> \
+        <select id="main_css_image"> \
             ' + set_data["image"] + ' \
         </select> \
-        <h3>1.6. ' + set_language[language]['other'] + '</h3> \
-        <input ' + set_data["include"] + ' type="checkbox" id="include" name="include" value="include"> ' + set_language[language]['include_link'] + ' \
+        <h3>1.6. ' + main_css_load_lang('other') + '</h3> \
+        <input ' + set_data["include"] + ' type="checkbox" id="main_css_include" value="include"> ' + main_css_load_lang('include_link') + ' \
+        <h3>1.7. ' + main_css_load_lang('set_toc') + '</h3> \
+        <select id="main_css_toc"> \
+            ' + set_data["toc"] + ' \
+        </select> \
+        <h3>1.8. ' + main_css_load_lang('set_font_size') + '</h3> \
+        <input id="main_css_font_size" placeholder="' + main_css_load_lang('font_size') + ' (EX : 11)" value="' + set_data["font_size"] + '"> \
+        <h2>2. ' + main_css_load_lang('editor') + '</h2> \
+        <h3>2.1. ' + main_css_load_lang('main') + '</h3> \
+        <input ' + set_data["monaco"] + ' type="checkbox" id="main_css_monaco" value="monaco"> ' + main_css_load_lang('use_monaco') + '<sup>(1)</sup> \
         <hr class="main_hr"> \
-        <input ' + set_data["image_paste"] + ' type="checkbox" id="image_paste" name="image_paste" value="image_paste"> 클립보드 이미지 업로드 (ko-KR) \
+        <input ' + set_data["image_paste"] + ' type="checkbox" id="main_css_image_paste" value="image_paste"> ' + 
+            main_css_load_lang('clipboard_upload') + '<sup>(ko-KR)</sup><sup>(1)</sup> \
         <hr class="main_hr"> \
-        <button onclick="main_css_get_post();">' + set_language[language]['save'] + '</button> \
+        <button onclick="main_css_get_post();">' + main_css_load_lang('save') + '</button> \
+        <hr class="main_hr"> \
+        <ul id="footnote_data"> \
+            <li><a id="note_1_end" href="#note_1">(1)</a> ' + main_css_load_lang('except_ie') + '</li> \
+            <li><a href="#note_1_1">(1.1)</a></li> \
+            <li><a id="note_2_end" href="#note_2">(ko-KR)</a> ' + main_css_load_lang('only_korean') + '</li> \
+        </ul> \
     ';
+
+    // 목차 구현
+    var toc_all_data = '<div id="toc"><span id="toc_title">TOC</span><br>';
+    var skin_set_data = document.getElementById("main_skin_set").innerHTML;
+    var split_toc;
+    var toc_data;
+    i = 1;
+    while(1) {
+        toc_data = skin_set_data.match(/<h[1-6]>([^<>]+)<\/h[1-6]>/);
+        if(toc_data) {
+            split_toc = toc_data[1].match(/^([^ ]+)(.+)/);
+            toc_all_data += '' + 
+                '<br>' +
+                '<span style="margin-left: ' + String(((toc_data[1].match(/\./g) || []).length - 1) * 10) + 'px;">' +
+                    '<a href="#toc_' + String(i) + '">' + split_toc[1] + '</a>' + split_toc[2] +
+                '</span>' +
+            '';
+
+            skin_set_data = skin_set_data.replace(
+                /<(h[1-6])>([^<>]+)<\/h[1-6]>/, 
+                '<$1 id="toc_' + String(i) + '"><a href="#toc">' + split_toc[1] + '</a>' + split_toc[2] + '</$1>'
+            );
+            i += 1;
+        } else {
+            break;
+        }
+    }
+    document.getElementById("main_skin_set").innerHTML = toc_all_data + '</div>' + skin_set_data;
+
+    // 각주 구현
+    skin_set_data = document.getElementById("main_skin_set").innerHTML;
+    var note_list = {};
+    var plus_note;
+    i = 1;
+    while(1) {
+        toc_data = skin_set_data.match(/<sup>([^<>]+)<\/sup>/);
+        if(toc_data) {
+            if(!note_list[toc_data[1]]) {
+                note_list[toc_data[1]] = [String(i), 0];
+            } else {
+                note_list[toc_data[1]][1] += 1;
+            }
+
+            if(note_list[toc_data[1]][1] != 0) {
+                plus_note = '_' + String(note_list[toc_data[1]][1]);
+            } else {
+                plus_note = '';
+            }
+            
+            skin_set_data = skin_set_data.replace(
+                /<sup>([^<>]+)<\/sup>/, 
+                '<sup><a id="note_' + note_list[toc_data[1]][0] + plus_note + '" href="#note_' + note_list[toc_data[1]][0] + '_end">$1</a></sup>'
+            );
+            i += 1;
+        } else {
+            break;
+        }
+    }
+    document.getElementById("main_skin_set").innerHTML = skin_set_data;    
 }

+ 45 - 1
views/main_css/js/load_something.js

@@ -23,4 +23,48 @@ function load_ver() {
             document.getElementById('ver_send').style.display = "list-item";
         }
     }
-}
+}
+
+function do_skin_ver_check() {
+    var url = "/api/skin_info?all=true";
+    var xhr = new XMLHttpRequest();
+    xhr.open("GET", url, true);
+    xhr.send(null);
+
+    xhr.onreadystatechange = function() {
+        if(this.readyState === 4 && this.status === 200) {
+            var json_data = JSON.parse(this.responseText);
+            var all_need_update = [];
+            for(var key in json_data) {
+                if(json_data[key]['lastest_version']) {
+                    var new_skin_ver = json_data[key]['lastest_version']['skin_ver'];
+                    var old_skin_ver = json_data[key]['skin_ver'];
+                    var skin_name = json_data[key]['name'];
+                    if(new_skin_ver !== old_skin_ver) {
+                        all_need_update.push(skin_name);
+                    }
+                }
+            }
+            
+            if(all_need_update.length !== 0) {
+                document.getElementById('need_skin_update').innerHTML += ' (' + (all_need_update.join(', ')) + ')';
+            }
+        }
+    }
+}
+
+function do_twofa_check(init = 0) {
+    var data_check = document.getElementById('twofa_check_input').checked;
+    document.getElementById('fa_plus_content').style.display = data_check === true ? "block" : "none";
+}
+
+function ie_end_support() {
+    if(document.currentScript === undefined) {
+        window.location = 'microsoft-edge:' + window.location;
+        setTimeout(function() {
+            window.location = 'https://go.microsoft.com/fwlink/?linkid=2135547';
+        }, 1);
+    }
+}
+
+ie_end_support();

+ 104 - 109
views/main_css/js/load_topic.js

@@ -1,67 +1,11 @@
-function topic_list_load(topic_num, s_num, where) {
-    var url = "/api/thread/" + String(topic_num) + "?render=1&num=" + String(s_num);
-    var n_data = "";
-
-    var xhr = new XMLHttpRequest();
-    xhr.open("GET", url, true);
-    xhr.send(null);
-
-    xhr.onreadystatechange = function() {
-        if(this.readyState === 4 && this.status === 200) {
-            var t_data = JSON.parse(this.responseText);
-            var t_plus_data = '';
-            
-            for(key in t_data) {
-                n_data += t_data[key]['data'];
-                t_plus_data += t_data[key]['plus_data'];
-            }
-
-            document.getElementById(where).innerHTML = n_data;
-            eval(t_plus_data);
-        }
-    }
-}
-
-function topic_plus_load(topic_num, num) {
-    var test = setInterval(function() {
-        var url = "/api/thread/" + String(topic_num) + "?num=" + num + "&render=1";
-        var n_data = '';
-        var n_num = 1;
-
-        var xhr = new XMLHttpRequest();
-        xhr.open("GET", url, true);
-        xhr.send(null);
-
-        xhr.onreadystatechange = function() {
-            if(this.readyState === 4 && this.status === 200 && this.responseText !== '{}\n') {
-                var t_data = JSON.parse(this.responseText);
-                var t_plus_data = '';
-
-                for(key in t_data) {
-                    n_data += t_data[key]['data'];
-                    n_num = key;
-
-                    t_plus_data += t_data[key]['plus_data'];
-                }
-
-                document.getElementById("plus_topic").innerHTML += n_data;
-                eval(t_plus_data);
-
-                topic_plus_load(topic_num, String(Number(num) + 1));
-                clearInterval(test);
-            }
-        }
-    }, 5000);
-}
-
-function topic_main_load(topic_num, s_num) {
-    if(s_num) {
-        var url = "/api/thread/" + String(topic_num) + "?render=1&num=" + s_num;
+function new_topic_load(topic_num, type_do = 'top', some = '', where = 'top_topic') {
+    if(type_do === 'top') {
+        var url = "/api/thread/" + topic_num + "?top=1";
+    } else if(type_do === 'main') {
+        var url = "/api/thread/" + topic_num;
     } else {
-        var url = "/api/thread/" + String(topic_num) + "?render=1";
+        var url = "/api/thread/" + topic_num + some;
     }
-    var n_data = "";
-    var num = 1;
 
     var xhr = new XMLHttpRequest();
     xhr.open("GET", url, true);
@@ -69,56 +13,107 @@ function topic_main_load(topic_num, s_num) {
 
     xhr.onreadystatechange = function() {
         if(this.readyState === 4 && this.status === 200) {
-            var t_data = JSON.parse(this.responseText);
-            var t_plus_data = '';
-
-            for(var key in t_data) {
-                n_data += t_data[key]['data'];
-                num = key;
-
-                t_plus_data += t_data[key]['plus_data'];
-            }
-
-            document.getElementById('main_topic').innerHTML = n_data;
-            eval(t_plus_data);
-
-            if(window.location.hash) {
-                document.getElementById(window.location.hash.replace(/^#/, '')).focus();
-            }
+            var data_t = JSON.parse(this.responseText);
+            var start = 0;
+            var key_v = '?num=1';
             
-            if(!s_num) {
-                topic_plus_load(topic_num, String(Number(num) + 1));
+            for(var key in data_t) {
+                var data_a = '';
+                if(start === 0) {
+                    var admin = data_t['data_main']['admin'];
+                    var ip_first = data_t['data_main']['ip_first'];
+                
+                    start = 1;
+                }
+                
+                if(key === 'data_main') {
+                    continue;
+                }
+                
+                key_v = '?num=' + String(Number(key) + 1);
+                
+                var color_b = '';
+                var color_t = '';
+                
+                var ip = data_t[key]['ip_pas'];
+                var ip_o = data_t[key]['ip'];
+                var blind = data_t[key]['blind'];
+                var data_i_pas = data_t[key]['data_pas'][0];
+                
+                if(data_i_pas === '') {
+                    data_i_pas = '<br>';
+                }
+                
+                if(blind === 'O') {
+                    color_b = 'toron_color_not';
+                } else {
+                    color_b = 'toron_color';
+                }
+                
+                if(blind === 'O') {
+                    ip += ' <a href="/admin_log?search=blind%20(code%20' + topic_num + '#' + key + '">(B)</a>';
+                    
+                    if(admin === '1') {
+                        ip += ' <a href="/thread/' + topic_num + '/raw/' + key + '">(R)</a>';
+                    }
+                }
+                
+                if(admin === '1' || blind !== 'O') {
+                    ip += ' <a href="/thread/' + topic_num + '/admin/' + key + '">(T)</a>';
+                }
+                
+                if(type_do === 'top') {
+                    color_t = 'toron_color_red';
+                } else if(blind === '1') {
+                    color_t = 'toron_color_blue';
+                } else if(ip_o === ip_first) {
+                    color_t = 'toron_color_green';
+                } else {
+                    color_t = 'toron_color';
+                }
+                
+                data_a += '' + 
+                    '<table id="toron">' + 
+                        '<tr>' + 
+                            '<td id="' + color_t + '">' + 
+                                '<a href="javascript:void(0);" id="' + key + '">#' + key + '</a> ' + 
+                                ip + 
+                                '<span style="float: right;">' + data_t[key]['date'] + '</span>' + 
+                            '</td>' + 
+                        '</tr>' + 
+                        '<tr>' + 
+                            '<td id="' + color_b + '">' + 
+                                '<div id="topic_scroll">' + data_i_pas + '</div>' + 
+                            '</td>' + 
+                        '</tr>' +
+                    '</table>' + 
+                    '<hr class="main_hr">' + 
+                ''
+
+                document.getElementById(where).innerHTML += data_a;
+                eval(data_t[key]['data_pas'][1]);
             }
-        }
-    }
-}
-
-function topic_top_load(topic_num) {
-    var url = "/api/thread/" + String(topic_num) + "?top=1&render=1";
-    var n_data = "";
-    var num = 1;
-
-    var xhr = new XMLHttpRequest();
-    xhr.open("GET", url, true);
-    xhr.send(null);
-
-    xhr.onreadystatechange = function() {
-        if(this.readyState === 4 && this.status === 200) {
-            var t_data = JSON.parse(this.responseText);
-            var t_plus_data = '';
-
-            for(var key in t_data) {
-                n_data += t_data[key]['data'];
-                num = key;
-
-                t_plus_data += t_data[key]['plus_data'];
+            
+            if(type_do === 'top') {
+                new_topic_load(topic_num, 'main', '', 'main_topic');
+            } else if(type_do === 'main') {
+                data_url_v = window.location.href.split('#');
+                if(data_url_v.length !== 0) {
+                    if(document.getElementById(data_url_v[1])) {
+                        document.getElementById(data_url_v[1]).focus();
+                    }
+                }
+                
+                new_topic_load(topic_num, 're', key_v, where);
+            } else if(type_do === 're') {
+                setTimeout(function() {
+                    if(start === 0) {
+                        new_topic_load(topic_num, 're', some, where);
+                    } else {
+                        new_topic_load(topic_num, 're', key_v, where);
+                    }
+                }, 2000);
             }
-
-            document.getElementById('top_topic').innerHTML = n_data;
-            eval(t_plus_data);
-
-            topic_main_load(topic_num, null);
         }
     }
-
 }

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


+ 69 - 34
views/main_css/js/load_namumark.js → views/main_css/js/render_namumark.js

@@ -2,12 +2,8 @@ function get_link_state(data, i = 0) {
     var get_class = document.getElementsByClassName(data + 'link_finder')[i];
     if(get_class) {
         var xhr = new XMLHttpRequest();
-        xhr.open(
-            "GET", 
-            get_class.href.replace('/w/', '/api/w/').replace(/#([^#]*)/, '') + "?exist=1", 
-            true
-        );
-        xhr.send(null);
+        xhr.open("GET", get_class.href.replace('/w/', '/api/w/').replace(/#([^#]*)/, '') + "?exist=1");
+        xhr.send();
 
         xhr.onreadystatechange = function() {
             if(this.readyState === 4 && this.status === 200) {
@@ -23,6 +19,14 @@ function get_link_state(data, i = 0) {
     }
 }
 
+function load_image_link(data) {
+    data.innerHTML = '' +
+        '<img   style="' + data.getAttribute('under_style') + '" ' + 
+                'alt="' + data.getAttribute('under_alt') + '" ' + 
+                'src="' + data.getAttribute('under_src') + '">' +
+    '';
+}
+
 function get_file_state(data, i = 0) {       
     var get_class = document.getElementsByClassName(data + 'file_finder')[i];
     if(get_class) {            
@@ -32,9 +36,24 @@ function get_file_state(data, i = 0) {
                 document.cookie.match(main_css_regex_data('main_css_image_set'))[1] === '1'
             ) {
                 document.getElementsByClassName(data + 'file_finder')[i].innerHTML = '' +
-                    '<a href="' + get_class.getAttribute('under_src') + '">(' +
-                        get_class.getAttribute('under_src') +
-                    ')</a>' +
+                    '<a href="' + get_class.getAttribute('under_src') + '" ' +
+                        'title="' + get_class.getAttribute('under_src') + '">' + 
+                        '(External image link)' + 
+                    '</a>' +
+                '';
+            } else if(
+                document.cookie.match(main_css_regex_data('main_css_image_set')) &&
+                document.cookie.match(main_css_regex_data('main_css_image_set'))[1] === '2'
+            ) {
+                document.getElementsByClassName(data + 'file_finder')[i].innerHTML = '' +
+                    '<a href="javascript:void(0);" ' +
+                        'onclick="load_image_link(this); this.onclick = \'\';" ' + 
+                        'under_style="' + get_class.getAttribute('under_style') + '" ' +
+                        'under_alt="' + get_class.getAttribute('under_alt') + '" ' +
+                        'under_src="' + get_class.getAttribute('under_src') + '" ' +
+                        'title="' + get_class.getAttribute('under_src') + '">' + 
+                        '(External image load)' + 
+                    '</a>' +
                 '';
             } else {
                 document.getElementsByClassName(data + 'file_finder')[i].innerHTML = '' +
@@ -45,12 +64,8 @@ function get_file_state(data, i = 0) {
             }
         } else {
             var xhr = new XMLHttpRequest();
-            xhr.open(
-                "GET", 
-                get_class.getAttribute('under_src').replace('/image/', '/api/image/'), 
-                true
-            );
-            xhr.send(null);
+            xhr.open("GET", get_class.getAttribute('under_src').replace('/image/', '/api/image/'));
+            xhr.send();
             
             xhr.onreadystatechange = function() {
                 if(this.readyState === 4 && this.status === 200) {
@@ -58,7 +73,7 @@ function get_file_state(data, i = 0) {
                         document.getElementsByClassName(data + 'file_finder')[i].innerHTML = '' +
                             '<a href="' + get_class.getAttribute('under_href') + '" ' + 
                                 'id="not_thing">' +
-                                get_class.getAttribute('under_alt') +
+                                '(' + get_class.getAttribute('under_alt') + ')' +
                             '</a>' +
                         '';
                     } else {
@@ -67,9 +82,22 @@ function get_file_state(data, i = 0) {
                             document.cookie.match(main_css_regex_data('main_css_image_set'))[1] === '1'
                         ) {
                             document.getElementsByClassName(data + 'file_finder')[i].innerHTML = '' +
-                                '<a href="' + get_class.getAttribute('under_src') + '">(' +
-                                    get_class.getAttribute('under_alt') +
-                                ')</a>' +
+                                '<a href="' + get_class.getAttribute('under_src') + '">' +
+                                    '(' + get_class.getAttribute('under_alt') + ')' +
+                                '</a>' +
+                            '';
+                        } else if(
+                            document.cookie.match(main_css_regex_data('main_css_image_set')) &&
+                            document.cookie.match(main_css_regex_data('main_css_image_set'))[1] === '2'
+                        ) {
+                            document.getElementsByClassName(data + 'file_finder')[i].innerHTML = '' +
+                                '<a href="javascript:void(0);" ' +
+                                    'onclick="load_image_link(this); this.onclick = \'\';" ' + 
+                                    'under_style="' + get_class.getAttribute('under_style') + '" ' +
+                                    'under_alt="' + get_class.getAttribute('under_alt') + '" ' +
+                                    'under_src="' + get_class.getAttribute('under_src') + '">' + 
+                                    '(' + get_class.getAttribute('under_alt') + ' load)' +
+                                '</a>' +
                             '';
                         } else {
                             document.getElementsByClassName(data + 'file_finder')[i].innerHTML = '' +
@@ -87,29 +115,36 @@ function get_file_state(data, i = 0) {
     }
 }
 
-function load_include(title, name, p_data) {
+function load_include(name_doc, name_ob, data_include, name_org = '') {
     var change = '';
-    for(key in p_data) {
-        change += '@' + p_data[key][0].replace('&', '<amp>') + '@,' + p_data[key][1].replace(',', '<comma>').replace('&', '<amp>') + ','
+    for(var key in data_include) {
+        change += '' +
+            '@' + data_include[key][0].replace('&', '<amp>') + '@,' + 
+            data_include[key][1].replace(',', '<comma>').replace('&', '<amp>') + ',' +
+        ''
     }
     
-    var url = "/api/w/" + encodeURI(title) + "?include=" + name + "&change=" + change;
+    var url = '' +
+        "/api/w/" + encodeURI(name_doc) + 
+        "?include=" + name_ob + 
+        "&change=" + change +
+        '&name_org=' + name_org +
+    '';
 
     var xhr = new XMLHttpRequest();
-    xhr.open("GET", url, true);
-    xhr.send(null);
+    xhr.open("GET", url);
+    xhr.send();
 
     xhr.onreadystatechange = function() {
         if(this.readyState === 4 && this.status === 200) {
             if(this.responseText === "{}\n") {
-                document.getElementById(name).innerHTML = "";
-                document.getElementsByClassName(name)[0].id = "not_thing";
+                document.getElementById(name_ob).innerHTML = "";
+                document.getElementsByClassName(name_ob)[0].href = "/w/" + do_url_change(name_doc); 
+                document.getElementsByClassName(name_ob)[0].id = "not_thing";
             } else {
-                var o_p_data = JSON.parse(this.responseText);
-                
-                document.getElementById(name).innerHTML = o_p_data['data'];
-                
-                eval(o_p_data['js_data']);
+                var data_load = JSON.parse(this.responseText);
+                document.getElementById(name_ob).innerHTML = data_load['data'];
+                eval(data_load['js_data']);
             }
         }
     }
@@ -119,8 +154,8 @@ function page_count() {
     var url = "/api/title_index";
 
     var xhr = new XMLHttpRequest();
-    xhr.open("GET", url, true);
-    xhr.send(null);
+    xhr.open("GET", url);
+    xhr.send();
 
     xhr.onreadystatechange = function() {
         if(this.readyState === 4 && this.status === 200) {

+ 564 - 0
views/main_css/js/render_onmark.js

@@ -0,0 +1,564 @@
+// Tool
+function do_url_change(data) {
+    return encodeURIComponent(data);
+}
+
+function do_link_change(data, data_nowiki, no_change = 0) {
+    data = data.replace(/^:/, '');
+    
+    if(no_change === 0) {
+        data = data.replace(/^사용자:/, 'user:');
+        data = data.replace(/^분류:/, 'category:');
+        data = data.replace(/^파일:/, 'file:');
+    }
+    
+    var data_var = data.split('#');
+    var link_main = data.replace(/#(.*)$/, '');
+    var link_sub = data_var.length !== 1 ? ('#' + data_var[data_var.length - 1]) : '';
+    
+    return [link_main, link_sub];
+}
+
+function do_js_safe_change(data) {
+    data = data.replace(/\\/g, '\\\\');
+    data = data.replace(/"/g, '\\"');
+    
+    return data;
+}
+
+function do_math_try_insert(name_ob, data) {
+    return '' + 
+        'try {\n' + 
+            'katex.render("' + data + '", document.getElementById(\"' + name_ob + '\"));\n' + 
+        '} catch {\n' + 
+            'document.getElementById(\"' + name_ob + '\").innerHTML = "<span style=\'color: red;\'>' + data + '</span>";\n' + 
+        '}\n' + 
+    ''
+}
+
+function do_data_try_insert(name_ob, data) {
+    return '' +
+        'if(document.getElementById("' + name_ob + '")) {\n' + 
+            'document.getElementById("' + name_ob + '").innerHTML = "' + data + '";\n' + 
+        '}\n' +
+    ''
+}
+
+function do_return_date() {
+    var today_data = new Date();
+
+    return '' +
+        String(today_data.getFullYear()) + '-' + 
+        ((today_data.getMonth() + 1) < 10 ? '0' : '') + String(today_data.getMonth() + 1) + '-' + 
+        (today_data.getDate() < 10 ? '0' : '') + String(today_data.getDate()) + ' ' + 
+        (today_data.getHours() < 10 ? '0' : '') + String(today_data.getHours()) + ':' + 
+        (today_data.getMinutes() < 10 ? '0' : '') + String(today_data.getMinutes()) + ':' + 
+        (today_data.getSeconds() < 10 ? '0' : '') + String(today_data.getSeconds()) +
+    '';
+}
+
+function do_xss_change(data) {
+    data = data.replace(/&lt;/g, '<');
+    data = data.replace(/&gt;/g, '>');
+    data = data.replace(/&amp;/g, '&');
+    
+    return data;
+}
+
+// Sub
+function do_onmark_text_render(data) {    
+    data = data.replace(/'''((?:(?!''').)+)'''/g, '<b>$1</b>');
+    data = data.replace(/''((?:(?!'').)+)''/g, '<i>$1</i>');
+    data = data.replace(/__((?:(?!__).)+)__/g, '<u>$1</u>');
+    data = data.replace(/\^\^((?:(?!\^\^).)+)\^\^/g, '<sup>$1</sup>');
+    data = data.replace(/,,((?:(?!,,).)+),,/g, '<sub>$1</sub>');
+    data = data.replace(/--((?:(?!--).)+)--/g, '<s>$1</s>');
+    data = data.replace(/~~((?:(?!~~).)+)~~/g, '<s>$1</s>');
+    
+    return data;
+}
+
+function do_onmark_heading_render(data) {
+    var heading_re = /\n(={1,6}) ?([^=]+) ?={1,6}\n/;
+    var heading_level_all = [0, 0, 0, 0, 0, 0];
+    var toc_data = '<div id="toc"><div id="toc_title">TOC</div>\n';
+    while(1) {        
+        var heading_data = data.match(heading_re);
+        if(!heading_data) {
+            break;
+        }
+          
+        var heading_level = heading_data[1].length;
+        heading_level_all[heading_level - 1] += 1;
+
+        var i = 6;
+        while(i > heading_level - 1) {
+            heading_level_all[i] = 0;
+
+            i -= 1;
+        }
+
+        heading_level = String(heading_level);
+        var heading_level_string = '';
+        i = 0;
+        while(i < 6) {
+            if(heading_level_all[i] !== 0) {
+                heading_level_string += String(heading_level_all[i]) + '.';
+            }
+
+            i += 1;
+        }
+        
+        var heading_level_string_no_end = heading_level_string.replace(/\.$/, '');
+
+        toc_data += '' +
+            '<span style="margin-left: ' + String((heading_level_string.match(/\./g).length - 1) * 10) + 'px;">' +
+                '<a href="#s-' + heading_level_string_no_end + '">' + 
+                    heading_level_string + ' ' +
+                '</a>' + heading_data[2] +
+            '</span>' +
+            '\n' +
+        ''
+        data = data.replace(heading_re, 
+            '<h' + heading_level + ' id="s-' + heading_level_string_no_end + '">' + 
+                '<a href="#toc">' + heading_level_string + '</a> ' + heading_data[2] + 
+            '</h' + heading_level + '>' +
+            '\n'
+       );
+    }
+    
+    data = data.replace(/\[(?:toc|목차)\]/g, toc_data + '</div>');
+    
+    return data;
+}
+
+function do_onmark_link_render(data, data_js, name_doc, name_include, data_nowiki) {
+    var num_link = 0;
+    var category_data = '';
+    var category_re = /^(분류|category):/i;
+    var file_re = /^(파일|file):/i;
+    data = data.replace(/\[\[(((?!\]\]).)+)\]\]/g, function(x, x_1) {
+        var link_split = x_1.split('|');
+        var link_real = link_split[0];
+        var link_out = link_split[1] ? link_split[1] : link_split[0];
+        var link_out_2 = link_split[1] ? link_split[1] : '';
+        
+        num_link += 1;
+        var num_link_str = String(num_link - 1);
+        if(link_real.match(file_re)) {
+            var file_name = link_real.replace(file_re, '');
+            console.log(file_name);
+            
+            return '';
+        } else if(link_real.match(category_re)) {
+            var category_link = link_real.replace(category_re, '');
+            
+            category_data = (category_data === '' ? '<div id="cate_all"><div id="cate">Category : ' : category_data);
+            category_data += '' +
+                '<a class="' + name_include + 'link_finder" ' +
+                    'href="/w/category:' + do_url_change(category_link) + '">' +
+                    category_link +
+                '</a> | ' +
+            ''
+            
+            return '';
+        } else if(link_real.match(/^http(s)?:\/\//)) {
+            var i = 0;
+            while(i < 2) {
+                if(i === 0) {
+                    var var_link_type = 'href';
+                } else {
+                    var var_link_type = 'title';
+                }
+                
+                data_js += '' +
+                    'document.getElementsByName("' + name_include + 'set_link_' + num_link_str + '")[0].' + var_link_type + ' = ' + 
+                        '"' + do_js_safe_change(link_real) + '";' +
+                    '\n' +
+                '';
+                
+                i += 1;
+            }
+            
+            return  '<a id="out_link" ' +
+                        'name="' + name_include + 'set_link_' + num_link_str + '" ' + 
+                        'title=""' +
+                        'href="">' + link_out + '</a>';
+        } else {
+            var i = 0;
+            while(i < 2) {
+                if(i === 0) {
+                    var link_data_var = do_link_change(link_real, data_nowiki);
+                    var link_main = link_data_var[0];
+                    var link_sub = link_data_var[1];
+                    
+                    var var_link_type = 'href';
+                    var var_link_data = '/w/' + do_url_change(link_main) + link_sub;
+                } else {
+                    var var_link_type = 'title';
+                    var var_link_data = do_js_safe_change(link_real);
+                }
+                
+                data_js += '' +
+                    'document.getElementsByName("' + name_include + 'set_link_' + num_link_str + '")[0].' + var_link_type + ' = ' + 
+                        '"' + var_link_data + '";' +
+                    '\n' +
+                '';
+                
+                i += 1;
+            }
+            
+            return  '<a class="' + name_include + 'link_finder" ' +
+                        'name="' + name_include + 'set_link_' + num_link_str + '" ' +
+                        'title="" ' +
+                        'href="">' + link_out + '</a>';
+        }
+    });
+    
+    data += (category_data === '' ? '' : (category_data.replace(/\| $/, '') + '</div></div>'));
+    
+    return [data, data_js];
+}
+
+function do_onmark_footnote_render(data, name_include) {
+    var footnote_end_data = '';
+    var footnote_all_data = {};
+    var footnote_re = /(?:\[\*([^ \]]*)(?: ((?:(?!\]).)+))?\]|\[(footnote|각주)\])/;
+    var i = 1;
+    while(1) {
+        var footnote_data = data.match(footnote_re);
+        if(!footnote_data) {
+            break;
+        }
+        
+        if(!footnote_data[3]) {
+            if(!footnote_data[2]) {
+                var footnote_line_data = '';
+            } else {
+                var footnote_line_data = footnote_data[2];
+            }
+            
+            if(!footnote_data[1]) {
+                var footnote_name = String(i);
+            } else {
+                var footnote_name = footnote_data[1];
+            }
+            
+            if(!footnote_all_data[footnote_name]) {
+                footnote_all_data[footnote_name] = footnote_line_data;
+            }
+
+            footnote_line_data = footnote_all_data[footnote_name];
+            
+            footnote_end_data += '' +
+                '<li>' +
+                    '<a href="javascript:do_open_foot(\'' + name_include + 'fn-' + String(i) + '\', 1);" ' +
+                        'id="' + name_include + 'cfn-' + String(i) + '">' +
+                        '(' + footnote_name + ')' +
+                    '</a> <span id="' + name_include + 'fn-' + String(i) + '">' + footnote_line_data + '</span>' +
+                '</li>' +
+            '';
+            data = data.replace(footnote_re, '' +
+                '<sup>' +
+                    '<a href="javascript:do_open_foot(\'' + name_include + 'fn-' + String(i) + '\', 0);" ' +
+                        'id="' + name_include + 'rfn-' + String(i) + '">' +
+                        '(' + footnote_name + ')' +
+                    '</a>' +
+                '</sup><span id="' + name_include + 'dfn-' + String(i) + '"></span>' +
+           '');
+            
+            i += 1;
+        } else {
+            if(footnote_end_data !== '') {
+                data = data.replace(footnote_re, '<ul id="footnote_data">' + footnote_end_data + '</ul>');    
+            }
+            
+            footnote_end_data = '';
+        }
+    }
+    
+    if(footnote_end_data !== '') {
+        data += '<ul id="footnote_data">' + footnote_end_data + '</ul>';
+    }
+    
+    return data;
+}
+
+function do_onmark_macro_render(data) {
+    data = data.replace(/\[([^[\](]+)\(((?:(?!\)\]).)+)\)\]/g, function(x, x_1, x_2) {
+        x_1 = x_1.toLowerCase();
+        if(x_1 === 'youtube' || x_1 === 'kakaotv' || x_1 === 'nicovideo') {
+            var video_code = x_2.match(/^([^,]+)/);
+            video_code = video_code ? video_code[1] : '';
+            
+            var video_width = x_2.match(/,(?: *)width=([0-9]+)/);
+            video_width = video_width ? (video_width[1] + 'px') : '640px';
+            
+            var video_height = x_2.match(/,(?: *)height=([0-9]+)/);
+            video_height = video_height ? (video_height[1] + 'px') : '360px';
+            
+            if(x_1 === 'youtube') {
+                var video_start = x_2.match(/,(?: *)start=([0-9]+)/);
+                video_start = video_start ? ('?' + video_start[1]) : '';
+                
+                video_code = video_code.replace(/^https:\/\/www\.youtube\.com\/watch\?v=/, '');
+                video_code = video_code.replace(/^https:\/\/youtu\.be\//, '');
+                
+                var video_src = 'https://www.youtube.com/embed/' + video_code + video_start
+            } else if(x_1 === 'kakaotv') {
+                video_code = video_code.replace(/^https:\/\/tv\.kakao\.com\/channel\/9262\/cliplink\//, '');
+                video_code = video_code.replace(/^http:\/\/tv\.kakao\.com\/v\//, '');
+                
+                var video_src = 'https://tv.kakao.com/embed/player/cliplink/' + video_code +'?service=kakao_tv'
+            } else {
+                var video_src = 'https://embed.nicovideo.jp/watch/' + video_code
+            }
+            
+            return '<iframe style="width: ' + video_width + '; height: ' + video_height + ';" src="' + video_src + '" frameborder="0" allowfullscreen></iframe>';
+        } else if(x_1 === 'anchor') {
+            return '<span id="' + x_2 + '"></span>';
+        } else {
+            return '<macro_start>' + x_1 + '(' + x_2 + ')<macro_end>';
+        }
+    });
+    
+    data = data.replace(/\[([^[*()\]]+)\]/g, function(x, x_1) {
+        x_1 = x_1.toLowerCase();
+        if(x_1 === 'date') {
+            return do_return_date();
+        } else if(x_1 === 'clearfix') {
+            return '<div style="clear:both"></div>';
+        } else if(x_1 === 'br') { 
+            return '<br>';
+        } else {
+            return '<macro_start>' + x_1 + '<macro_end>';
+        }
+    });
+    
+    data = data.replace(/<macro_start>/g, '[');
+    data = data.replace(/<macro_end>/g, ']');
+    
+    return data;
+}
+
+function do_onmark_middle_render(data, data_js, name_include) {
+    var middle_stack = [];
+    var middle_re = /(?:{{{([^{} ]+)|(}}}))/;
+    
+    var syntax_on = 0;
+    
+    var html_n = 0;
+    
+    while(1) {
+        var middle_data = data.match(middle_re);
+        if(!middle_data) {
+            break;
+        }
+        
+        if(middle_data[2]) {
+            if(middle_stack.length === 0) {
+                data = data.replace(middle_re, '<middle_end>');   
+            } else {
+                data = data.replace(middle_re, middle_stack[middle_stack.length - 1]);    
+                middle_stack.pop();
+            }
+        } else {
+            if(middle_data[1].match(/^(?:(#(?:[0-9a-f-A-F]{3}){1,2})|#([a-zA-Z]+))/)) {
+                var color = middle_data[1].match(/^(?:(#(?:[0-9a-f-A-F]{3}){1,2})|#([a-zA-Z]+))/);
+                color = color[1] ? color[1] : color[2];
+                
+                data = data.replace(middle_re, '<span style="color: ' + color + ';">');
+                middle_stack.push('</span>');
+            } else if(middle_data[1].match(/^(\+|-)([1-5])/)) {
+                var font = middle_data[1].match(/^(\+|-)([1-5])/);
+                if(font[1] === '+') {
+                    var font_size = String(100 + (20 * Number(font[2]))) + '%';
+                } else {
+                    var font_size = String(100 - (10 * Number(font[2]))) + '%';
+                }
+                
+                data = data.replace(middle_re, '<span style="font-size: ' + font_size + ';">');
+                middle_stack.push('</span>');
+            } else if(middle_data[1] === '#!wiki') {
+                var wiki_re = /{{{#!wiki(?: style=["']([^"']*)["']\n)?/;
+                
+                var wiki = data.match(wiki_re);
+                var wiki_style = wiki[1] ? wiki[1] : '';
+                
+                data = data.replace(wiki_re, '<div_wiki_start style="' + wiki_style + '">');  
+                middle_stack.push('<div_wiki_end>');
+            } else if(middle_data[1] === '#!html') {
+                html_n += 1;
+                
+                data = data.replace(middle_re, '<span id="' + name_include + 'render_contect_' + String(html_n) + '">');
+                middle_stack.push('</span>');
+            } else if(middle_data[1] === '#!folding') {
+                data = data.replace(middle_re, '<div>');
+                middle_stack.push('</div>');
+            } else {
+                data = data.replace(middle_re, '<middle_start>' + middle_data[1]);   
+            }
+        }
+    }
+    
+    while(middle_stack.length !== 0) {
+        data += middle_stack[middle_stack.length - 1];
+        middle_stack.pop();
+    }
+    
+    data = data.replace(/\n<div_wiki_end>/g, '<div_wiki_end>');
+    
+    data = data.replace(/<middle_start>/g, '{{{');
+    data = data.replace(/<middle_end>/g, '}}}');
+    
+    return [data, data_js];
+}
+
+function do_onmark_last_render(data) {
+    // middle_render 마지막 처리
+    data = data.replace(/<div_wiki_start /g, '<div ');
+    data = data.replace(/<div_wiki_end>/g, '</div>');
+    
+    // heading_render 마지막 처리
+    data = data.replace(/(<\/h[0-9]>)\n/g, '$1');
+    
+    // list_render 마지막 처리
+    data = data.replace(/(<\/ul>)\n/g, '$1');
+    
+    // br 마지막 처리
+    data = data.replace(/^(\n| )+/, '');
+    data = data.replace(/(\n| )+$/, '');
+    data = data.replace(/\n/g, '<br>');
+    
+    return data;
+}
+
+function do_onmark_include_render(data, data_js, name_include) {
+    var include_re = /\[include\(((?:(?!\)\]).)+)\)\]/;
+    var i = 0;
+    while(1) {
+        i += 1;
+        
+        var include_data = data.match(include_re);
+        if(!include_data) {
+            break;
+        }
+        
+        data = data.replace(include_re,
+            '<a id="' + name_include + 'include_link" class="include_' + String(i) + '" href="">(' + include_data[1] + ')</a>' +
+            '<div id="' + name_include + 'include_' + String(i) + '"></div>'
+        );
+        
+        data_js += 'load_include("' + do_js_safe_change(include_data[1]) + '", "' + name_include + 'include_' + String(i) + '", []);\n'
+    }
+    
+    return [data, data_js];
+}
+
+function do_onmark_nowiki_before_render(data, data_js, name_include, data_nowiki, num_nowiki = 0) {
+    data = data.replace(/\\(.)/g, function(x, x_1) {
+        num_nowiki += 1;
+        data_nowiki[name_include + 'nowiki_' + String(num_nowiki)] = x_1;
+        data_js += do_data_try_insert(name_include + 'nowiki_' + String(num_nowiki), do_js_safe_change(x_1));
+        return '<span id="' + name_include + 'nowiki_' + String(num_nowiki) + '"></span>';
+    });
+    
+    return [data, data_js, data_nowiki, num_nowiki];
+}
+
+function do_onmark_table_render(data) {
+    return data;
+}
+
+function do_onmark_list_render(data) {
+    var list_re = /\n((?:(?:(?: )+)\* (?:(?:(?!\n).)+)\n)+)/;
+    var list_short_re = /((?: )+)\* ((?:(?!\n).)+)\n/g;
+    while(1) {
+        var list_data = data.match(list_re);
+        if(!list_data) {
+            break;
+        }
+        
+        var list_end_data = '<ul>' + list_data[1].replace(list_short_re, function(x, x_1, x_2) {
+            return '<li style="margin-left: ' + String(x_1.length * 20) + 'px;">' + x_2 + '</li>';
+        }) + '</ul>';
+
+        data = data.replace(list_re, '\n' + list_end_data + '\n');
+    }
+    
+    return data;
+}
+
+function do_onmark_math_render(data, data_js, name_include) {
+    data = data.replace(/<math>((?:(?!<\/math>).)+)<\/math>/g, '[math($1)]');
+    
+    var i = 0;
+    data = data.replace(/\[math\((((?!\)]).)+)\)]/g, function(x, x_1) {
+        i += 1;
+        
+        data_js += do_math_try_insert(name_include + 'math_' + String(i), do_js_safe_change(do_xss_change(x_1)));
+        return '<span id="' + name_include + 'math_' + String(i) + '"></span>';
+    });
+    
+    return [data, data_js];
+}
+
+// Main
+function do_onmark_render(test_mode = 1, name_id = '', name_include = '', name_doc = '') {    
+	if(test_mode === 0) {
+        var data = '\n' + document.getElementById(name_id).innerHTML.replace(/\r/g, '') + '\n';
+    } else {
+    	var data = '\n' + (
+``
+        ) + '\n';
+    }
+    var data_js = '';
+    var data_backlink = [];
+    var data_nowiki = {};
+    
+    var data_var = do_onmark_math_render(data, data_js, name_include);
+    data = data_var[0];
+    data_js = data_var[1];
+    
+    data_var = do_onmark_nowiki_before_render(data, data_js, name_include, data_nowiki);
+    data = data_var[0];
+    data_js = data_var[1];
+    data_nowiki = data_var[2];
+    var num_nowiki = data_var[3];
+    
+    data_var = do_onmark_include_render(data, data_js, name_include);
+    data = data_var[0];
+    data_js = data_var[1];
+    
+    data_var = do_onmark_middle_render(data, data_js, name_include);
+    data = data_var[0];
+    data_js = data_var[1];
+    
+    data = do_onmark_text_render(data);
+    data = do_onmark_heading_render(data);
+    data = do_onmark_table_render(data);
+    
+    data_var = do_onmark_link_render(data, data_js, name_doc, name_include, data_nowiki);
+    data = data_var[0];
+    data_js = data_var[1];
+    
+    data = do_onmark_macro_render(data);
+    data = do_onmark_list_render(data);
+    data = do_onmark_footnote_render(data, name_include);
+    data = do_onmark_last_render(data, name_include);
+    
+    data_js += '' + 
+        'get_link_state("' + name_include + '");\n' + 
+        'get_file_state("' + name_include + '");\n' + 
+    ''
+    data_js = 'render_html("' + name_include + 'render_contect");\n' + data_js
+    
+    if(test_mode === 0) {
+        document.getElementById(name_id).innerHTML = data;
+        eval(data_js);
+    } else {
+    	console.log([data, data_js]);
+    }
+}
+
+do_onmark_render();

+ 1 - 9
views/marisa/css/main.css

@@ -4,7 +4,7 @@ body {
     word-wrap: break-word;
     margin: 0;
     font-family: 'Apple SD Gothic', '맑은고딕', 'Nanum Gothic', 'Noto Sans KR', sans-serif;
-    font-size: 14px;
+    font-size: 0.85rem;
 }
 
 ul {
@@ -333,14 +333,6 @@ textarea, input {
     color: white;
 }
 
-blockquote {
-    padding: 1em calc(2em + 25px) 1em 1em;
-    margin: 1em 0em 0em;
-    background-color: #eeeeee;
-    border: 1px dashed #ccc;
-    border-left: 5px solid black;
-}
-
 #out_link::before {
     content: '🅴';
     font-weight: lighter;

+ 3 - 3
views/marisa/index.html

@@ -8,10 +8,10 @@
             <title>{{imp[0]}} - {{imp[1][0]}}</title>
         {% endif %}
         {{imp[3][3]|safe}}
-        <link rel="stylesheet" href="/views/marisa/css/main.css?ver=16">
-        <script src="/views/marisa/js/skin_set.js?ver=5"></script>
+        <link rel="stylesheet" href="/views/marisa/css/main.css?ver=17">
+        <script src="/views/marisa/js/skin_set.js?ver=6"></script>
         <script src="/views/marisa/js/main.js?ver=3"></script>
-        <script>main_load(); window.addEventListener('DOMContentLoaded', function() { skin_set(); });</script>
+        <script>main_load(); window.addEventListener('DOMContentLoaded', skin_set);</script>
         <script src="https://code.iconify.design/1/1.0.3/iconify.min.js"></script>
         <link rel="shortcut icon" href="/views/main_css/file/favicon.ico?ver=1">
         {{imp[1][5]|safe}}

+ 2 - 8
views/marisa/js/main.js

@@ -23,13 +23,7 @@ function opening(data) {
 }
 
 document.onclick = function(event) {
-    for(var node = event.target; node != document.body; node = node.parentNode) {
-        if(save_data !== '' && open == 0) {
-            if(node.id === save_data) {
-                break;
-            } else {
-                document.getElementById(save_data).style.display = 'none';
-            }
-        }
+    if(save_data !== '' && open == 0) {
+        document.getElementById(save_data).style.display = 'none';
     }
 }

+ 7 - 7
views/marisa/js/skin_set.js

@@ -1,9 +1,9 @@
 function get_post() {
     check = document.getElementById('invert');
     if(check.checked === true) {
-        document.cookie = 'invert=1;';
+        document.cookie = 'main_css_darkmode=1;';
     } else {
-        document.cookie = 'invert=0;';
+        document.cookie = 'main_css_darkmode=0;';
     }
 
     history.go(0);
@@ -12,11 +12,11 @@ function get_post() {
 function main_load() {
     var head_data = document.querySelector('head');
     if(
-        cookies.match(regex_data('invert')) &&
-        cookies.match(regex_data('invert'))[1] === '1'
+        cookies.match(regex_data('main_css_darkmode')) &&
+        cookies.match(regex_data('main_css_darkmode'))[1] === '1'
     ) {
         head_data.innerHTML += '' +
-            '<link rel="stylesheet" href="/views/main_css/css/sub/dark.css?ver=1">' +
+            '<link rel="stylesheet" href="/views/main_css/css/sub/dark.css?ver=2">' +
             '<link rel="stylesheet" href="/views/marisa/css/dark.css?ver=6">' +
         '';
     }
@@ -53,8 +53,8 @@ function skin_set() {
         var set_data = {};
 
         if(
-            cookies.match(regex_data('invert')) &&
-            cookies.match(regex_data('invert'))[1] === '1'
+            cookies.match(regex_data('main_css_darkmode')) &&
+            cookies.match(regex_data('main_css_darkmode'))[1] === '1'
         ) {
             set_data["invert"] = "checked";
         }