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

Merge pull request #716 from 2du/master

뉴 월드
잉여개발기 (SPDV) 6 лет назад
Родитель
Сommit
97d4a531ac
60 измененных файлов с 1452 добавлено и 918 удалено
  1. 38 17
      app.py
  2. 1 2
      data/app_var.json
  3. 2 2
      data/oauthsettings.json
  4. 17 0
      emergency_tool.py
  5. 15 7
      language/en-US.json
  6. 30 0
      language/help_tool.py
  7. 297 289
      language/ko-KR.json
  8. 1 4
      requirements.txt
  9. 11 0
      route/api_markup.py
  10. 9 6
      route/api_raw.py
  11. 34 9
      route/api_skin_info.py
  12. 88 20
      route/api_topic_sub.py
  13. 66 0
      route/api_user_info.py
  14. 14 11
      route/api_w.py
  15. 17 5
      route/edit.py
  16. 44 9
      route/func_upload.py
  17. 8 8
      route/give_acl.py
  18. 0 1
      route/give_user_ban.py
  19. 25 1
      route/inter_wiki.py
  20. 5 1
      route/inter_wiki_del.py
  21. 25 5
      route/inter_wiki_plus.py
  22. 1 1
      route/list_acl.py
  23. 1 0
      route/list_admin_use.py
  24. 3 0
      route/main_manager.py
  25. 29 20
      route/main_views.py
  26. 5 15
      route/recent_changes.py
  27. 27 0
      route/recent_history_delete.py
  28. 53 0
      route/recent_history_tool.py
  29. 13 3
      route/setting.py
  30. 5 4
      route/setting_adsense.py
  31. 28 75
      route/tool/func.py
  32. 4 4
      route/tool/init.py
  33. 3 0
      route/tool/mark.py
  34. 14 0
      route/tool/set_mark/markdown.py
  35. 16 28
      route/tool/set_mark/namu.py
  36. 18 0
      route/tool/set_mark/tool.py
  37. 23 116
      route/topic.py
  38. 31 49
      route/topic_admin.py
  39. 26 10
      route/topic_close_list.py
  40. 67 36
      route/topic_stop.py
  41. 27 32
      route/topic_tool.py
  42. 4 43
      route/user_info.py
  43. 6 2
      route/view_diff_data.py
  44. 1 1
      route/view_down.py
  45. 45 20
      route/view_read.py
  46. 7 2
      route/watch_list.py
  47. 2 2
      version.json
  48. 53 3
      views/easter_egg.html
  49. 3 2
      views/main_css/css/main.css
  50. 0 19
      views/main_css/js/do_preview.js
  51. 34 0
      views/main_css/js/load_preview.js
  52. 15 0
      views/main_css/js/load_user_info.js
  53. 10 0
      views/main_css/js/render_markdown.js
  54. 23 0
      views/main_css/js/topic_list_load.js
  55. 0 31
      views/main_css/js/topic_load.js
  56. 45 0
      views/main_css/js/topic_main_load.js
  57. 38 0
      views/main_css/js/topic_plus_load.js
  58. 1 1
      views/main_css/js/topic_reload.js
  59. 24 0
      views/main_css/js/topic_top_load.js
  60. 0 2
      views/neo_yousoro/css/main.css

+ 38 - 17
app.py

@@ -15,8 +15,11 @@ c_ver = version_list['master']['c_ver']
 s_ver = version_list['master']['s_ver']
 s_ver = version_list['master']['s_ver']
 
 
 print('Version : ' + r_ver)
 print('Version : ' + r_ver)
+print('DB set version : ' + c_ver)
+print('Skin set version : ' + s_ver)
+print('----')
 
 
-app_var = json.loads(open('data/app_variables.json', encoding='utf-8').read())
+app_var = json.loads(open('data/app_var.json', encoding='utf-8').read())
 
 
 # DB
 # DB
 all_src = []
 all_src = []
@@ -26,7 +29,7 @@ for i_data in os.listdir("."):
         all_src += [f_src.groups()[0]]
         all_src += [f_src.groups()[0]]
 
 
 if len(all_src) == 0:
 if len(all_src) == 0:
-    print('DB\'s name (data) : ', end = '')
+    print('DB name (data) : ', end = '')
     
     
     db_name = input()
     db_name = input()
     if db_name == '':
     if db_name == '':
@@ -39,8 +42,10 @@ elif len(all_src) > 1:
 
 
         db_num += 1
         db_num += 1
 
 
-    print('Number : ', end = '')    
+    print('----')
+    print('Number : ', end = '')
     db_name = all_src[int(number_check(input())) - 1]
     db_name = all_src[int(number_check(input())) - 1]
+    print('----')
 else:
 else:
     db_name = all_src[0]
     db_name = all_src[0]
 
 
@@ -113,7 +118,6 @@ if setup_tool == 0:
 
 
 if setup_tool != 0:
 if setup_tool != 0:
     create_data = {}
     create_data = {}
-
     create_data['all_data'] = [
     create_data['all_data'] = [
         'data', 
         'data', 
         'cache_data', 
         'cache_data', 
@@ -157,9 +161,9 @@ if setup_tool != 0:
     create_data['ua_d'] = ['name', 'ip', 'ua', 'today', 'sub']
     create_data['ua_d'] = ['name', 'ip', 'ua', 'today', 'sub']
     create_data['filter'] = ['name', 'regex', 'sub']
     create_data['filter'] = ['name', 'regex', 'sub']
     create_data['scan'] = ['user', 'title']
     create_data['scan'] = ['user', 'title']
-    create_data['acl'] = ['title', 'dec', 'dis', 'view', 'why']
+    create_data['acl'] = ['title', 'decu', 'dis', 'view', 'why']
     create_data['inter'] = ['title', 'link']
     create_data['inter'] = ['title', 'link']
-    create_data['html_filter'] = ['html', 'kind']
+    create_data['html_filter'] = ['html', 'kind', 'plus']
     create_data['oauth_conn'] = ['provider', 'wiki_id', 'sns_id', 'name', 'picture']
     create_data['oauth_conn'] = ['provider', 'wiki_id', 'sns_id', 'name', 'picture']
 
 
     for create_table in create_data['all_data']:
     for create_table in create_data['all_data']:
@@ -288,7 +292,7 @@ else:
         
         
 conn.commit()
 conn.commit()
 
 
-## Func
+# Func
 @app.route('/del_alarm')
 @app.route('/del_alarm')
 def alarm_del():
 def alarm_del():
     return alarm_del_2(conn)
     return alarm_del_2(conn)
@@ -297,15 +301,15 @@ def alarm_del():
 def alarm():
 def alarm():
     return alarm_2(conn)
     return alarm_2(conn)
 
 
-@app.route('/<regex("inter_wiki|(?:edit|email|file|name)_filter"):tools>')
+@app.route('/<regex("inter_wiki|edit_top|image_license|(?:edit|email|file|name)_filter"):tools>')
 def inter_wiki(tools = None):
 def inter_wiki(tools = None):
     return inter_wiki_2(conn, tools)
     return inter_wiki_2(conn, tools)
 
 
-@app.route('/<regex("del_(?:inter_wiki|(?:edit|email|file|name)_filter)"):tools>/<name>')
+@app.route('/<regex("del_(?:inter_wiki|edit_top|image_license|(?:edit|email|file|name)_filter)"):tools>/<name>')
 def inter_wiki_del(tools = None, name = None):
 def inter_wiki_del(tools = None, name = None):
     return inter_wiki_del_2(conn, tools, name)
     return inter_wiki_del_2(conn, tools, name)
 
 
-@app.route('/<regex("plus_(?:inter_wiki|(?:edit|email|file|name)_filter)"):tools>', methods=['POST', 'GET'])
+@app.route('/<regex("plus_(?:inter_wiki|edit_top|image_license|(?:edit|email|file|name)_filter)"):tools>', methods=['POST', 'GET'])
 @app.route('/<regex("plus_edit_filter"):tools>/<name>', methods=['POST', 'GET'])
 @app.route('/<regex("plus_edit_filter"):tools>/<name>', methods=['POST', 'GET'])
 def inter_wiki_plus(tools = None, name = None):
 def inter_wiki_plus(tools = None, name = None):
     return inter_wiki_plus_2(conn, tools, name)
     return inter_wiki_plus_2(conn, tools, name)
@@ -439,9 +443,9 @@ def topic_block(name = None, sub = None, num = 1):
 def topic_top(name = None, sub = None, num = 1):
 def topic_top(name = None, sub = None, num = 1):
     return topic_top_2(conn, name, sub, num)
     return topic_top_2(conn, name, sub, num)
                 
                 
-@app.route('/topic/<everything:name>/sub/<sub>/tool/<regex("close|stop|agree"):tool>', methods=['POST', 'GET'])
-def topic_stop(name = None, sub = None, tool = None):
-    return topic_stop_2(conn, name, sub, tool)
+@app.route('/topic/<everything:name>/sub/<sub>/setting', methods=['POST', 'GET'])
+def topic_stop(name = None, sub = None):
+    return topic_stop_2(conn, name, sub)
 
 
 @app.route('/topic/<everything:name>/sub/<sub>/tool')
 @app.route('/topic/<everything:name>/sub/<sub>/tool')
 def topic_tool(name = None, sub = None):
 def topic_tool(name = None, sub = None):
@@ -534,7 +538,15 @@ def list_user_topic(name = None):
 @app.route('/<regex("history"):tool>/<everything:name>', methods=['POST', 'GET'])
 @app.route('/<regex("history"):tool>/<everything:name>', methods=['POST', 'GET'])
 def recent_changes(name = None, tool = 'record'):
 def recent_changes(name = None, tool = 'record'):
     return recent_changes_2(conn, name, tool)
     return recent_changes_2(conn, name, tool)
+
+@app.route('/history_tool/<everything:name>')
+def recent_history_tool(name = None):
+    return recent_history_tool_2(conn, name)
     
     
+@app.route('/history_delete/<everything:name>', methods=['POST', 'GET'])
+def recent_history_delete(name = None):
+    return recent_history_delete_2(conn, name)
+
 @app.route('/upload', methods=['GET', 'POST'])
 @app.route('/upload', methods=['GET', 'POST'])
 def func_upload():
 def func_upload():
     return func_upload_2(conn)
     return func_upload_2(conn)
@@ -586,14 +598,23 @@ def api_version():
     return api_version_2(conn, r_ver, c_ver)
     return api_version_2(conn, r_ver, c_ver)
 
 
 @app.route('/api/skin_info')
 @app.route('/api/skin_info')
-def api_skin_info():
-    return api_skin_info_2(conn)
+@app.route('/api/skin_info/<name>')
+def api_skin_info(name = ''):
+    return api_skin_info_2(conn, name)
+
+@app.route('/api/markup')
+def api_markup():
+    return api_markup_2(conn)
+
+@app.route('/api/user_info/<name>')
+def api_user_info(name = ''):
+    return api_user_info_2(conn, name)
 
 
 @app.route('/api/topic/<everything:name>/sub/<sub>')
 @app.route('/api/topic/<everything:name>/sub/<sub>')
 def api_topic_sub(name = '', sub = '', time = ''):
 def api_topic_sub(name = '', sub = '', time = ''):
     return api_topic_sub_2(conn, name, sub, time)
     return api_topic_sub_2(conn, name, sub, time)
     
     
-## File
+# File
 @app.route('/views/easter_egg.html')
 @app.route('/views/easter_egg.html')
 def main_easter_egg():
 def main_easter_egg():
     return main_easter_egg_2(conn)
     return main_easter_egg_2(conn)
@@ -606,7 +627,7 @@ def main_views(name = None):
 def main_file(data = None):
 def main_file(data = None):
     return main_file_2(conn, data)
     return main_file_2(conn, data)
 
 
-## End
+# End
 @app.errorhandler(404)
 @app.errorhandler(404)
 def main_error_404(e):
 def main_error_404(e):
     return main_error_404_2(conn)
     return main_error_404_2(conn)

+ 1 - 2
data/app_variables.json → data/app_var.json

@@ -1,6 +1,5 @@
 {
 {
-    "_README" : "DO NOT MODIFY THIS FILE.",
+    "_conment_1_" : "Don't edit this file.",
     "path_oauth_setting" : "data/oauthsettings.json",
     "path_oauth_setting" : "data/oauthsettings.json",
-    "path_set_json" : "data/set.json",
     "path_data_image" : "data/images"
     "path_data_image" : "data/images"
 }
 }

+ 2 - 2
data/oauthsettings.json

@@ -1,7 +1,7 @@
 {
 {
     "_README" : {
     "_README" : {
-        "en" : "To use the oAuth login feature, you must set the 'publish_url' value to a domain address that includes the HTTPS protocol, and actually support HTTPS connections.",
-        "ko" : "oAuth 로그인 기능을 사용하려면 'publish_url' 값을 HTTPS 프로토콜을 포함한 도메인 주소로 설정하고, 실제로 HTTPS 연결을 지원해야 합니다.",
+        "en" : "To use the OAuth login feature, you must set the 'publish_url' value to a domain address that includes the HTTPS protocol, and actually support HTTPS connections.",
+        "ko" : "OAuth 로그인 기능을 사용하려면 'publish_url' 값을 HTTPS 프로토콜을 포함한 도메인 주소로 설정하고, 실제로 HTTPS 연결을 지원해야 합니다.",
         "support" : ["discord", "facebook", "naver", "kakao"]
         "support" : ["discord", "facebook", "naver", "kakao"]
     },
     },
     "publish_url" : "https://",
     "publish_url" : "https://",

+ 17 - 0
emergency_tool.py

@@ -14,13 +14,17 @@ elif len(all_src) > 1:
 
 
     for i_data in all_src:
     for i_data in all_src:
         print(str(db_num) + ' : ' + i_data)
         print(str(db_num) + ' : ' + i_data)
+        
+        db_num += 1
 
 
+    print('----')
     print('Number : ', end = '')    
     print('Number : ', end = '')    
     db_name = all_src[int(number_check(input())) - 1]
     db_name = all_src[int(number_check(input())) - 1]
 else:
 else:
     db_name = all_src[0]
     db_name = all_src[0]
 
 
 if len(all_src) == 1:
 if len(all_src) == 1:
+    print('----')
     print('DB\'s name : ' + db_name)
     print('DB\'s name : ' + db_name)
 
 
 conn = sqlite3.connect(db_name + '.db', check_same_thread = False)
 conn = sqlite3.connect(db_name + '.db', check_same_thread = False)
@@ -28,6 +32,7 @@ curs = conn.cursor()
 
 
 load_conn(conn)
 load_conn(conn)
 
 
+print('----')
 print('1. Backlink reset')
 print('1. Backlink reset')
 print('2. reCAPTCHA delete')
 print('2. reCAPTCHA delete')
 print('3. Ban delete')
 print('3. Ban delete')
@@ -38,6 +43,7 @@ print('7. Change password')
 print('8. Reset version')
 print('8. Reset version')
 print('9. New DB create')
 print('9. New DB create')
 
 
+print('----')
 print('Select : ', end = '')
 print('Select : ', end = '')
 what_i_do = input()
 what_i_do = input()
 
 
@@ -65,6 +71,7 @@ elif what_i_do == '2':
     curs.execute("delete from other where name = 'recaptcha'")
     curs.execute("delete from other where name = 'recaptcha'")
     curs.execute("delete from other where name = 'sec_re'")
     curs.execute("delete from other where name = 'sec_re'")
 elif what_i_do == '3':
 elif what_i_do == '3':
+    print('----')
     print('IP or Name : ', end = '')
     print('IP or Name : ', end = '')
     user_data = input()
     user_data = input()
 
 
@@ -83,29 +90,37 @@ elif what_i_do == '3':
         ])
         ])
     curs.execute("delete from ban where block = ?", [user_data])
     curs.execute("delete from ban where block = ?", [user_data])
 elif what_i_do == '4':
 elif what_i_do == '4':
+    print('----')
     print('Host : ', end = '')
     print('Host : ', end = '')
     host = input()
     host = input()
 
 
     curs.execute("update other set data = ? where name = 'host'", [host])
     curs.execute("update other set data = ? where name = 'host'", [host])
 elif what_i_do == '5':
 elif what_i_do == '5':
+    print('----')
     print('Port : ', end = '')
     print('Port : ', end = '')
     port = int(input())
     port = int(input())
 
 
     curs.execute("update other set data = ? where name = 'port'", [port])
     curs.execute("update other set data = ? where name = 'port'", [port])
 elif what_i_do == '6':
 elif what_i_do == '6':
+    print('----')
     print('Skin\'s name : ', end = '')
     print('Skin\'s name : ', end = '')
     skin = input()
     skin = input()
 
 
     curs.execute("update other set data = ? where name = 'skin'", [skin])
     curs.execute("update other set data = ? where name = 'skin'", [skin])
 elif what_i_do == '7':
 elif what_i_do == '7':
+    print('----')
     print('1. sha256')
     print('1. sha256')
     print('2. sha3')
     print('2. sha3')
+    
+    print('----')
     print('Select : ', end = '')
     print('Select : ', end = '')
     what_i_do = int(input())
     what_i_do = int(input())
 
 
+    print('----')
     print('User\'s name : ', end = '')
     print('User\'s name : ', end = '')
     user_name = input()
     user_name = input()
 
 
+    print('----')
     print('User\'s password : ', end = '')
     print('User\'s password : ', end = '')
     user_pw = input()
     user_pw = input()
 
 
@@ -121,6 +136,7 @@ elif what_i_do == '7':
 elif what_i_do == '8':
 elif what_i_do == '8':
     curs.execute("update other set data = '00000' where name = 'ver'")
     curs.execute("update other set data = '00000' where name = 'ver'")
 else:
 else:
+    print('----')
     print('DB\'s name (data) : ', end = '')
     print('DB\'s name (data) : ', end = '')
     
     
     db_name = input()
     db_name = input()
@@ -131,4 +147,5 @@ else:
 
 
 conn.commit()
 conn.commit()
 
 
+print('----')
 print('OK')
 print('OK')

+ 15 - 7
language/en-US.json

@@ -87,6 +87,7 @@
         "start" : "Start",
         "start" : "Start",
         "pass" : "Passing",
         "pass" : "Passing",
         "file_name" : "File name",
         "file_name" : "File name",
+        "pinned" : "Pinned",
         "_comment_1.1_" : "Time",
         "_comment_1.1_" : "Time",
             "second" : "Second(s)",
             "second" : "Second(s)",
             "hour" : "Hour(s)",
             "hour" : "Hour(s)",
@@ -124,7 +125,7 @@
         "authorize" : "Authorize",
         "authorize" : "Authorize",
         "indexing" : "DB Indexing",
         "indexing" : "DB Indexing",
         "hide_release" : "Unhide",
         "hide_release" : "Unhide",
-        "notice_release" : "Release notice",
+        "pinned_release" : "Unpinned",
         "ban_release" : "Unblock",
         "ban_release" : "Unblock",
         "discussion_tool" : "Discussion tools",
         "discussion_tool" : "Discussion tools",
         "discussion_raw" : "Discussion[s] raw",
         "discussion_raw" : "Discussion[s] raw",
@@ -164,6 +165,13 @@
         "email_change" : "Email change",
         "email_change" : "Email change",
         "acl_change" : "Change document ACL",
         "acl_change" : "Change document ACL",
         "user_tool" : "User tool",
         "user_tool" : "User tool",
+        "skin_info" : "Skin info",
+        "closed_discussion" : "Closed discussion",
+        "agreed_discussion" : "Agreed discussion",
+        "history_delete" : "History delete",
+        "markup" : "Markup",
+        "title" : "Title",
+        "direct_input" : "Direct input",
         "_comment_2.1_" : "Filter",
         "_comment_2.1_" : "Filter",
             "_comment_2.1.1_" : "List",
             "_comment_2.1.1_" : "List",
                 "interwiki_list" : "Interwiki(s) list",
                 "interwiki_list" : "Interwiki(s) list",
@@ -171,12 +179,16 @@
                 "id_filter_list" : "ID filter(s) list",
                 "id_filter_list" : "ID filter(s) list",
                 "edit_filter_list" : "Contents filter(s) list",
                 "edit_filter_list" : "Contents filter(s) list",
                 "file_filter_list" : "File name filter(s) list",
                 "file_filter_list" : "File name filter(s) list",
+                "edit_tool_list" : "Edit tool(s) list",
+                "image_license_list" : "Image license(s) list",
             "_comment_2.1.2_" : "Add",
             "_comment_2.1.2_" : "Add",
                 "interwiki_add" : "Interwiki add",
                 "interwiki_add" : "Interwiki add",
                 "edit_filter_add" : "Contents filter add",
                 "edit_filter_add" : "Contents filter add",
                 "id_filter_add" : "ID filter add",
                 "id_filter_add" : "ID filter add",
                 "email_filter_add" : "Email filter add",
                 "email_filter_add" : "Email filter add",
                 "file_filter_add" : "File name filter add",
                 "file_filter_add" : "File name filter add",
+                "edit_tool_add" : "Edit tool add",
+                "image_license_add" : "Image license add",
         "_comment_2.2_" : "Setting",
         "_comment_2.2_" : "Setting",
             "setting" : "Setting",
             "setting" : "Setting",
             "restart_required" : "Restart required",
             "restart_required" : "Restart required",
@@ -217,6 +229,8 @@
                 "email_insert_text" : "Email input box text",
                 "email_insert_text" : "Email input box text",
                 "password_search_text" : "Password finder text",
                 "password_search_text" : "Password finder text",
                 "reset_user_text" : "Password reset complete text",
                 "reset_user_text" : "Password reset complete text",
+                "error_401" : "ACL view limited document notice",
+                "error_404" : "Missing document notice",
             "_comment_2.2.4_" : "Google",
             "_comment_2.2.4_" : "Google",
                 "recaptcha" : "reCAPTCHA",
                 "recaptcha" : "reCAPTCHA",
                 "google_imap" : "Google IMAP",
                 "google_imap" : "Google IMAP",
@@ -257,12 +271,6 @@
         "_comment_2.5_" : "Topic tool",
         "_comment_2.5_" : "Topic tool",
             "topic_tool" : "Discussion tool",
             "topic_tool" : "Discussion tool",
             "topic_state" : "Discussion status",
             "topic_state" : "Discussion status",
-            "topic_stop" : "Stop discussion",
-            "topic_close" : "Close discussion",
-            "topic_restart" : "Discussion restart",
-            "topic_open" : "Open discussion",
-            "topic_agreement" : "Discussion agreement",
-            "topic_destruction" : "Cancel discussion agreement",
         "_comment_2.6_" : "Period",
         "_comment_2.6_" : "Period",
             "1_day" : "1 day",
             "1_day" : "1 day",
             "5_day" : "5 days",
             "5_day" : "5 days",

+ 30 - 0
language/help_tool.py

@@ -0,0 +1,30 @@
+import re
+import json
+
+o_json = json.loads(open('en-US.json', encoding='utf-8').read())
+
+print('n_name : ', end = '')
+n_name = input()
+n_json = json.loads(open(n_name + '.json', encoding='utf-8').read())
+
+print()
+for i in list(n_json):
+    if not i in o_json:
+        del n_json[i]
+
+for i in list(o_json):
+    if not re.search('^_', i[0]):
+        if not i in n_json:
+            print('o_title : ' + i)
+            print('o_text : ' + o_json[i])
+
+            print('n_text : ', end = '')
+            n_text = input()
+
+            n_json = {**n_json, **{i : n_text}}
+
+n_data = json.dumps(n_json, indent = 4, ensure_ascii = False)
+
+f = open(n_name + '.json', "w", encoding='utf-8')
+f.write(n_data)
+f.close()

+ 297 - 289
language/ko-KR.json

@@ -1,291 +1,299 @@
 {
 {
-    "server" : "서버",
-    "filter" : "필터",
-    "delete" : "삭제",
-    "notice" : "알림",
-    "add" : "추가",
-    "license" : "저작권",
-    "etc" : "기타",
-    "name" : "이름",
-    "regex" : "정규표현식",
-    "id" : "아이디",
-    "list" : "목록",
-    "main" : "메인",
-    "return" : "돌아가기",
-    "skin" : "스킨",
-    "save" : "저장",
-    "secret_key" : "비밀키",
-    "host" : "호스트",
-    "port" : "포트",
-    "restart" : "재시작",
-    "document_name" : "문서명",
-    "discussion_name" : "토론명",
-    "user_name" : "사용자 이름",
-    "go" : "이동",
-    "document" : "문서",
-    "discussion" : "토론",
-    "backlink" : "역링크",
-    "closed" : "닫힘",
-    "reload" : "다시 로드",
-    "send" : "전송",
-    "ongoing" : "진행중",
-    "normal" : "보통",
-    "range" : "범위",
-    "search" : "검색",
-    "raw" : "원본",
-    "history" : "역사",
-    "user_discussion" : "사용자 토론",
-    "record" : "기록",
-    "state" : "상태",
-    "revert" : "복원",
-    "why" : "사유",
-    "edit" : "편집",
-    "preview" : "미리보기",
-    "move" : "이동",
-    "upload" : "업로드",
-    "version" : "버전",
-    "stop" : "중지",
-    "close" : "닫기",
-    "open" : "열기",
-    "agreement" : "동의",
-    "template" : "틀",
-    "category" : "분류",
-    "file" : "파일",
-    "writer" : "작성자",
-    "editor" : "에디터",
-    "hide" : "숨김",
-    "check" : "검사",
-    "destruction" : "취소",
-    "tool" : "도구",
-    "recent" : "최근",
-    "password" : "비밀번호",
-    "login" : "로그인",
-    "logout" : "로그아웃",
-    "register" : "회원가입",
-    "language" : "언어",
-    "compare" : "비교",
-    "email" : "이메일",
-    "key" : "키",
-    "all" : "전체",
-    "sub" : "하위",
-    "create" : "생성",
-    "acl" : "ACL",
-    "upper" : "상위",
-    "other" : "기타",
-    "random" : "랜덤",
-    "error" : "오류",
-    "next" : "다음",
-    "previous" : "이전",
-    "authority" : "권한",
-    "connect" : "연결",
-    "explanation" : "설명",
-    "default" : "기본값",
-    "lastest" : "최신",
-    "type" : "유형",
-    "in_progress" : "진행중",
-    "start" : "시작",
-    "pass" : "넘기기",
-    "file_name" : "파일명",
-    "second" : "초",
-    "hour" : "시간",
-    "limitless" : "무기한",
-    "time" : "시간",
-    "period" : "기간",
-    "end" : "끝",
-    "user" : "사용자",
-    "admin" : "관리자",
-    "owner" : "소유자",
-    "ip" : "IP",
-    "member" : "가입자",
-    "ban" : "차단",
-    "blocked" : "차단됨",
-    "release" : "차단 해제",
-    "wiki_restart" : "위키 엔진 재시작",
-    "update" : "업데이트",
-    "need_document" : "필요한 문서들",
-    "close_discussion" : "닫힌 토론",
-    "open_discussion" : "열린 토론",
-    "recent_discussion" : "최근 토론",
-    "recent_change" : "최근 편집",
-    "edit_filter" : "편집 필터",
-    "recent_ban" : "최근 차단",
-    "load" : "다른 문서 불러오기",
-    "edit_filter_rule" : "편집 필터 규칙",
-    "move_history" : "이동 기록",
-    "other_tool" : "기타 도구",
-    "admin_tool" : "관리 도구",
-    "check_user" : "사용자 검사",
-    "compare_target" : "비교 대상 이름",
-    "authorize" : "권한 부여",
-    "indexing" : "DB 인덱싱",
-    "hide_release" : "표시",
-    "notice_release" : "릴리즈 노트",
-    "ban_release" : "차단 해제",
-    "discussion_tool" : "토론 도구",
-    "discussion_raw" : "토론 원본",
-    "oauth_signin_facebook" : "Facebook 아이디로 로그인",
-    "oauth_signin_naver" : "네이버 아이디로 로그인",
-    "oauth_signin_discord" : "디스코드 아이디로 로그인",
-    "oauth_signin_kakao" : "카카오톡 아이디로 로그인",
-    "connection" : "연결",
-    "new_connection" : "연결...",
-    "user_setting" : "사용자 설정",
-    "now_password" : "현재 비밀번호",
-    "new_password" : "새 비밀번호",
-    "password_confirm" : "비밀번호 확인",
-    "oauth_connection" : "Oauth 연결",
-    "password_search" : "비밀번호 찾기",
-    "login_able" : "로그인 가능",
-    "band_ban" : "대역 차단",
-    "band_blocked" : "대역 차단됨",
-    "document_acl" : "문서 ACL",
-    "discussion_acl" : "토론 ACL",
-    "view_acl" : "읽기 ACL",
-    "under_category" : "하위 분류",
-    "count" : "기여 횟수",
-    "alarm" : "알림",
-    "user_document" : "사용자 문서",
-    "user_head" : "사용자 <head>",
-    "user_document_acl" : "사용자 문서 ACL",
-    "encryption_method" : "암호화 방식",
-    "check_key" : "인증키 검사",
-    "reset_user_ok" : "검사 성공",
-    "name_or_ip_or_regex" : "ID or IP or 정규식",
-    "ban_period" : "차단 기간",
-    "not_sure" : "확실하지 않음",
-    "use_push_alarm" : "푸쉬 알림 사용",
-    "edit_button_paragraph" : "문단",
-    "password_change" : "비밀번호 변경",
-    "email_change" : "이메일 변경",
-    "acl_change" : "문서 ACL 변경",
-    "interwiki_list" : "인터위키 목록",
-    "email_filter_list" : "이메일 필터 목록",
-    "id_filter_list" : "ID 필터 목록",
-    "edit_filter_list" : "편집 필터 목록",
-    "file_filter_list" : "파일명 필터 목록",
-    "interwiki_add" : "인터위키 추가",
-    "edit_filter_add" : "편집 필터 추가",
-    "id_filter_add" : "ID 필터 추가",
-    "email_filter_add" : "이메일 필터 추가",
-    "file_filter_add" : "파일명 필터 추가",
-    "setting" : "설정",
-    "restart_required" : "재시작 필요",
-    "oauth_setting" : "OAuth 설정",
-    "adsense_setting" : "애드센스 설정",
-    "adsense_enable" : "애드센스 사용",
-    "skin_setting" : "스킨 설정",
-    "main_setting" : "메인 설정",
-    "text_setting" : "문구 설정",
-    "main_head" : "전역 <head>",
-    "main_body" : "전역 <body>",
-    "wiki_name" : "위키 이름",
-    "wiki_logo" : "위키 로고",
-    "main_page" : "대문",
-    "bottom_text" : "하단 텍스트",
-    "max_file_size" : "파일 최대 파일 크기",
-    "backup_interval" : "백업 주기",
-    "wiki_skin" : "위키 스킨",
-    "default_acl" : "기본 수정 ACL",
-    "default_discussion_acl" : "기본 토론 ACL",
-    "no_register" : "가입불가",
-    "hide_ip" : "IP 숨기기",
-    "wiki_host" : "위키 호스트",
-    "wiki_port" : "위키 포트",
-    "wiki_secret_key" : "위키 비밀키",
-    "email_required" : "이메일 필요",
-    "google_imap_required" : "Google IMAP 설정 필요",
-    "update_branch" : "업데이트를 가져올 브랜치",
-    "register_text" : "회원가입 정책",
-    "non_login_alert" : "비로그인 알림",
-    "edit_bottom_text" : "편집창 하단 문구",
-    "check_key_text" : "인증키 검사 문구",
-    "email_title" : "이메일 제목",
-    "email_text" : "이메일 내용",
-    "email_insert_text" : "이메일 입력란 문구",
-    "password_search_text" : "비밀번호 찾기 문구",
-    "reset_user_text" : "암호 초기화 완료 문구",
-    "recaptcha" : "reCAPTCHA",
-    "google_imap" : "Google IMAP",
-    "google_email" : "Google 이메일",
-    "google_app_password" : "Google 앱 비밀번호",
-    "open_discussion_list" : "열린 토론 목록",
-    "discussion_list" : "토론 목록",
-    "admin_list" : "관리자 목록",
-    "member_list" : "사용자 목록",
-    "authority_use_list" : "권한 사용 목록",
-    "admin_group_list" : "관리자 그룹 목록",
-    "all_document_list" : "모든 문서 목록",
-    "watchlist" : "주시 목록",
-    "acl_document_list" : "ACL 문서 목록",
-    "acl_required" : "ACL 필요",
-    "admin_group_add" : "관리자 그룹 권한 부여",
-    "ban_authority" : "차단 권한",
-    "discussion_authority" : "토론 관리 권한",
-    "user_check_authority" : "사용자 검사 권한",
-    "document_acl_authority" : "문서 ACL 관리 권한",
-    "history_hide_authority" : "역사 숨김 권한",
-    "authorization_authority" : "권한 부여 권한",
-    "owner_authority" : "소유자 권한",
-    "edit_record" : "편집 기록",
-    "discussion_record" : "토론 기록",
-    "edit_button_link" : "링크",
-    "edit_button_footnote" : "각주",
-    "edit_button_macro" : "매크로",
-    "edit_button_color" : "색상",
-    "edit_button_bold" : "강조",
-    "edit_button_strike" : "취소선",
-    "edit_button_big" : "크게",
-    "topic_tool" : "토론 도구",
-    "topic_state" : "토론 상태",
-    "topic_stop" : "토론 중지",
-    "topic_close" : "토론 닫기",
-    "topic_restart" : "토론 중지 해제",
-    "topic_open" : "토론 열기",
-    "topic_agreement" : "토론 합의",
-    "topic_destruction" : "토론 합의 취소",
-    "1_day" : "1일",
-    "5_day" : "5일",
-    "30_day" : "30일",
-    "180_day" : "180일",
-    "360_day" : "360일",
-    "admin_acl" : "관리자만",
-    "member_acl" : "가입자만",
-    "50_edit_acl" : "기여 횟수 총합 50회 이상 가입자만",
-    "all_acl" : "모든 사용자",
-    "email_acl" : "이메일을 가진 유저만",
-    "ie_no_data_required" : "이 기능을 수행하는데 필요한 데이터가 제공되지 않았습니다.",
-    "oauth_settings_not_found" : "관리자가 이 기능을 수행하는데 필요한 데이터를 제공하지 않았습니다.",
-    "oauth_disabled" : "관리자가 이 기능을 비활성화시켰습니다.",
-    "http_warring" : "경고: HTTPS 연결을 사용하지 않는다면 개인정보가 유출될 수 있습니다. 이 사항에 의해 입는 피해는 사용자에게 책임이 있음을 알려드립니다.",
-    "user_head_warring" : "비로그인시 브라우저를 닫거나 로그인시 사용자의 <head>는 삭제됩니다.",
-    "no_login_warring" : "비로그인 상태입니다. 편집시 지금 접속한 IP 명의로 기록됩니다.",
-    "user_reset_sign" : "사용자의 계정 정보가 다음과 같이 변경 되었습니다.",
-    "update_warring" : "최신 버전보다 0.2 버전 이상 낮은 경우 수동 업데이트를 권장 드립니다. 윈도우의 경우 route 폴더의 내용이 사라집니다.",
-    "markup_enabled" : "문법 사용 가능",
-    "update_error" : "자동 업데이트가 지원되지 않습니다.",
-    "inter_error" : "내부 오류.",
-    "authority_error" : "권한이 없습니다.",
-    "no_login_error" : "비로그인 상태입니다.",
-    "no_exist_user_error" : "계정이 존재하지 않습니다.",
-    "no_admin_block_error" : "관리자는 검사, 차단을 수행할 수 없습니다.",
-    "skin_error" : "이 스킨은 설정을 지원하지 않습니다.",
-    "same_id_exist_error" : "이미 같은 이름의 계정이 있습니다.",
-    "long_id_error" : "ID는 20자보다 짧아야 합니다.",
-    "id_char_error" : "오직 한글과 알파벳, 공백만 사용 가능합니다.",
-    "file_exist_error" : "파일이 존재하지 않습니다.",
-    "password_error" : "비밀번호가 다릅니다.",
-    "recaptcha_error" : "'나는 로봇이 아닙니다'를 통해 reCAPTCHA를 수행하세요.",
-    "file_extension_error" : "오직 JPG, GIF, JPEG, PNG, WEBP 만 업로드할 수 있습니다.",
-    "edit_record_error" : "수정 요약은 500자를 넘길 수 없습니다.",
-    "same_file_error" : "똑같은 이름의 파일이 존재합니다.",
-    "file_capacity_error" : "최대 파일 크기 (MB) :",
-    "decument_exist_error" : "이동하려는 이름에 이미 문서가 존재합니다.",
-    "password_diffrent_error" : "입력한 비밀번호와 비밀번호 확인이 서로 다릅니다.",
-    "edit_filter_error" : "편집 필터에 의해 금지된 단어가 사용되었습니다.",
-    "file_name_error" : "파일 이름에는 알파벳, 한글, 공백, 밑줄 과 빼기 기호만 사용할 수 있습니다.",
-    "topic_long_error" : "토론 이름이 256자를 넘지 않아야 합니다.",
-    "email_error" : "이런 이메일을 가진 사용자가 없습니다.",
-    "regex_error" : "정규표현식에 오류가 있습니다.",
-    "decument_404_error" : "이 문서는 존재하지 않습니다.",
-    "user_tool" : "사용자 도구"
+    "document_name": "문서명",
+    "non_login_alert": "비로그인 알림",
+    "hide": "숨기기",
+    "discussion_acl": "토론 ACL",
+    "ongoing": "진행중",
+    "user_tool": "사용자 도구",
+    "compare_target": "비교 대상 이름",
+    "email_title": "이메일 제목",
+    "acl_required": "ACL 필요",
+    "blocked": "차단됨",
+    "authorization_authority": "권한 부여 권한",
+    "open_discussion": "열린 토론",
+    "move_history": "이동 기록",
+    "register": "회원가입",
+    "reset_user_text": "암호 초기화 완료 문구",
+    "no_register": "가입불가",
+    "view_acl": "읽기 ACL",
+    "notice": "알림",
+    "login": "로그인",
+    "google_imap": "Google IMAP",
+    "close": "닫기",
+    "closed": "닫힘",
+    "start": "시작",
+    "ban_release": "차단 해제",
+    "encryption_method": "암호화 방식",
+    "why": "사유",
+    "user_check_authority": "사용자 검사 권한",
+    "second": "초",
+    "load": "다른 문서 불러오기",
+    "user_discussion": "사용자 토론",
+    "upper": "상위",
+    "email": "이메일",
+    "closed_discussion": "닫힌 토론",
+    "acl": "ACL",
+    "history_hide_authority": "역사 숨김 권한",
+    "go": "이동",
+    "edit_button_bold": "강조",
+    "document_acl": "문서 ACL",
+    "secret_key": "비밀키",
+    "raw": "원본",
+    "file": "파일",
+    "state": "상태",
+    "authorize": "권한 부여",
+    "check_user": "사용자 검사",
+    "email_acl": "이메일을 가진 유저만",
+    "email_error": "이런 이메일을 가진 사용자가 없습니다.",
+    "version": "버전",
+    "open": "열기",
+    "update_branch": "업데이트를 가져올 브랜치",
+    "edit_filter_error": "편집 필터에 의해 금지된 단어가 사용되었습니다.",
+    "ip": "IP",
+    "pinned_release": "고정 해제",
+    "next": "다음",
+    "password_change": "비밀번호 변경",
+    "hour": "시간",
+    "connect": "연결",
+    "edit_record": "편집 기록",
+    "preview": "미리보기",
+    "no_login_error": "비로그인 상태입니다.",
+    "upload": "업로드",
+    "user_name": "사용자 이름",
+    "member_acl": "가입자만",
+    "search": "검색",
+    "etc": "기타",
+    "edit_filter": "편집 필터",
+    "no_exist_user_error": "계정이 존재하지 않습니다.",
+    "compare": "비교",
+    "password_error": "비밀번호가 다릅니다.",
+    "default": "기본값",
+    "wiki_name": "위키 이름",
+    "edit_button_big": "크게",
+    "acl_document_list": "ACL 문서 목록",
+    "connection": "연결",
+    "oauth_disabled": "관리자가 이 기능을 비활성화시켰습니다.",
+    "random": "랜덤",
+    "filter": "필터",
+    "band_blocked": "대역 차단됨",
+    "password_diffrent_error": "입력한 비밀번호와 비밀번호 확인이 서로 다릅니다.",
+    "180_day": "180일",
+    "edit_button_footnote": "각주",
+    "markup_enabled": "문법 사용 가능",
+    "all_acl": "모든 사용자",
+    "send": "전송",
+    "not_sure": "확실하지 않음",
+    "file_name_error": "파일 이름에는 알파벳, 한글, 공백, 밑줄 과 빼기 기호만 사용할 수 있습니다.",
+    "pass": "넘기기",
+    "recaptcha_error": "'나는 로봇이 아닙니다'를 통해 reCAPTCHA를 수행하세요.",
+    "file_capacity_error": "최대 파일 크기 (MB) :",
+    "setting": "설정",
+    "end": "끝",
+    "error": "오류",
+    "oauth_signin_discord": "디스코드 아이디로 로그인",
+    "ban": "차단",
+    "email_insert_text": "이메일 입력란 문구",
+    "check_key_text": "인증키 검사 문구",
+    "other_tool": "기타 도구",
+    "recent_discussion": "최근 토론",
+    "oauth_signin_naver": "네이버 아이디로 로그인",
+    "record": "기록",
+    "owner_authority": "소유자 권한",
+    "wiki_port": "위키 포트",
+    "limitless": "무기한",
+    "normal": "일반",
+    "reset_user_ok": "검사 성공",
+    "in_progress": "진행중",
+    "under_category": "하위 분류",
+    "range": "범위",
+    "edit_filter_rule": "편집 필터 규칙",
+    "oauth_connection": "Oauth 연결",
+    "hide_ip": "IP 숨기기",
+    "topic_tool": "토론 도구",
+    "user_document": "사용자 문서",
+    "id": "아이디",
+    "no_login_warring": "비로그인 상태입니다. 편집시 지금 접속한 IP 명의로 기록됩니다.",
+    "edit_button_link": "링크",
+    "decument_404_error": "이 문서는 존재하지 않습니다.",
+    "key": "키",
+    "lastest": "최신",
+    "now_password": "현재 비밀번호",
+    "same_file_error": "똑같은 이름의 파일이 존재합니다.",
+    "same_id_exist_error": "이미 같은 이름의 계정이 있습니다.",
+    "max_file_size": "최대 파일 크기",
+    "new_password": "새 비밀번호",
+    "authority_use_list": "권한 사용 목록",
+    "alarm": "알림",
+    "main_body": "전역 <body>",
+    "all_document_list": "모든 문서 목록",
+    "update": "업데이트",
+    "login_able": "로그인 가능",
+    "discussion_tool": "토론 도구",
+    "regex": "정규표현식",
+    "file_filter_add": "파일명 필터 추가",
+    "wiki_restart": "위키 엔진 재시작",
+    "oauth_settings_not_found": "관리자가 이 기능을 수행하는데 필요한 데이터를 제공하지 않았습니다.",
+    "discussion_raw": "토론 원본",
+    "main_setting": "메인 설정",
+    "password": "비밀번호",
+    "update_error": "자동 업데이트가 지원되지 않습니다.",
+    "need_document": "필요한 문서들",
+    "sub": "하위",
+    "default_acl": "기본 수정 ACL",
+    "template": "틀",
+    "user_document_acl": "사용자 문서 ACL",
+    "password_confirm": "비밀번호 확인",
+    "pinned": "고정",
+    "edit_filter_add": "편집 필터 추가",
+    "ban_authority": "차단 권한",
+    "file_extension_error": "오직 JPG, GIF, JPEG, PNG, WEBP 만 업로드할 수 있습니다.",
+    "host": "호스트",
+    "email_text": "이메일 내용",
+    "recent": "최근",
+    "admin_acl": "관리자만",
+    "wiki_host": "위키 호스트",
+    "error_404": "없는 문서 문구",
+    "member_list": "사용자 목록",
+    "register_text": "회원가입 정책",
+    "interwiki_list": "인터위키 목록",
+    "email_change": "이메일 변경",
+    "edit_button_paragraph": "문단",
+    "edit_button_macro": "매크로",
+    "check": "검사",
+    "admin": "관리자",
+    "edit_filter_list": "편집 필터 목록",
+    "wiki_skin": "위키 스킨",
+    "admin_group_add": "관리자 그룹 권한 부여",
+    "all": "전체",
+    "skin_error": "이 스킨은 설정을 지원하지 않습니다.",
+    "member": "가입자",
+    "backlink": "역링크",
+    "no_admin_block_error": "관리자는 검사, 차단을 수행할 수 없습니다.",
+    "recaptcha": "reCAPTCHA",
+    "create": "생성",
+    "restart": "재시작",
+    "oauth_setting": "OAuth 설정",
+    "edit_bottom_text": "편집창 하단 문구",
+    "authority": "권한",
+    "document": "문서",
+    "decument_exist_error": "이동하려는 이름에 이미 문서가 존재합니다.",
+    "skin_setting": "스킨 설정",
+    "discussion_list": "토론 목록",
+    "restart_required": "재시작 필요",
+    "save": "저장",
+    "delete": "삭제",
+    "file_exist_error": "파일이 존재하지 않습니다.",
+    "text_setting": "문구 설정",
+    "document_acl_authority": "문서 ACL 관리 권한",
+    "wiki_logo": "위키 로고",
+    "edit_button_color": "색상",
+    "google_imap_required": "Google IMAP 설정 필요",
+    "adsense_setting": "애드센스 설정",
+    "google_email": "Google 이메일",
+    "previous": "이전",
+    "edit_button_strike": "취소선",
+    "name_or_ip_or_regex": "ID or IP or 정규식",
+    "editor": "에디터",
+    "wiki_secret_key": "위키 비밀키",
+    "band_ban": "대역 차단",
+    "http_warring": "경고: HTTPS 연결을 사용하지 않는다면 개인정보가 유출될 수 있습니다. 이 사항에 의해 입는 피해는 사용자에게 책임이 있음을 알려드립니다.",
+    "update_warring": "최신 버전보다 0.2 버전 이상 낮은 경우 수동 업데이트를 권장 드립니다. 윈도우의 경우 route 폴더의 내용이 사라집니다.",
+    "discussion_name": "토론명",
+    "discussion": "토론",
+    "main": "메인",
+    "server": "서버",
+    "admin_tool": "관리 도구",
+    "interwiki_add": "인터위키 추가",
+    "return": "돌아가기",
+    "logout": "로그아웃",
+    "bottom_text": "하단 텍스트",
+    "30_day": "30일",
+    "topic_long_error": "토론 이름이 256자를 넘지 않아야 합니다.",
+    "error_401": "ACL 보기 제한 문서 문구",
+    "history": "역사",
+    "admin_group_list": "관리자 그룹 목록",
+    "time": "시간",
+    "password_search_text": "비밀번호 찾기 문구",
+    "agreed_discussion": "합의된 토론",
+    "explanation": "설명",
+    "name": "이름",
+    "period": "기간",
+    "writer": "작성자",
+    "oauth_signin_facebook": "Facebook 아이디로 로그인",
+    "long_id_error": "ID는 20자보다 짧아야 합니다.",
+    "edit_record_error": "수정 요약은 500자를 넘길 수 없습니다.",
+    "revert": "복원",
+    "discussion_authority": "토론 관리 권한",
+    "user_setting": "사용자 설정",
+    "admin_list": "관리자 목록",
+    "add": "추가",
+    "check_key": "인증키 검사",
+    "file_filter_list": "파일명 필터 목록",
+    "5_day": "5일",
+    "email_filter_list": "이메일 필터 목록",
+    "user_reset_sign": "사용자의 계정 정보가 다음과 같이 변경 되었습니다.",
+    "ban_period": "차단 기간",
+    "use_push_alarm": "푸쉬 알림 사용",
+    "email_filter_add": "이메일 필터 추가",
+    "oauth_signin_kakao": "카카오톡 아이디로 로그인",
+    "authority_error": "권한이 없습니다.",
+    "type": "유형",
+    "acl_change": "문서 ACL 변경",
+    "owner": "소유자",
+    "password_search": "비밀번호 찾기",
+    "file_name": "파일명",
+    "close_discussion": "닫힌 토론",
+    "language": "언어",
+    "id_char_error": "오직 한글과 알파벳, 공백만 사용 가능합니다.",
+    "id_filter_add": "ID 필터 추가",
+    "skin": "스킨",
+    "user_head": "사용자 <head>",
+    "agreement": "동의",
+    "stop": "중지",
+    "ie_no_data_required": "이 기능을 수행하는데 필요한 데이터가 제공되지 않았습니다.",
+    "port": "포트",
+    "reload": "다시 로드",
+    "indexing": "DB 인덱싱",
+    "topic_state": "토론 상태",
+    "watchlist": "주시 목록",
+    "main_page": "대문",
+    "default_discussion_acl": "기본 토론 ACL",
+    "user": "사용자",
+    "skin_info": "스킨 정보",
+    "new_connection": "연결...",
+    "discussion_record": "토론 기록",
+    "move": "이동",
+    "recent_change": "최근 편집",
+    "destruction": "취소",
+    "count": "기여 횟수",
+    "main_head": "전역 <head>",
+    "recent_ban": "최근 차단",
+    "google_app_password": "Google 앱 비밀번호",
+    "id_filter_list": "ID 필터 목록",
+    "other": "기타",
+    "edit": "편집",
+    "open_discussion_list": "열린 토론 목록",
+    "user_head_warring": "비로그인시 브라우저를 닫거나 로그인시 사용자의 <head>는 삭제됩니다.",
+    "email_required": "이메일 필요",
+    "1_day": "1일",
+    "regex_error": "정규표현식에 오류가 있습니다.",
+    "backup_interval": "백업 주기",
+    "license": "라이선스",
+    "hide_release": "숨김 해제",
+    "360_day": "360일",
+    "inter_error": "내부 오류.",
+    "50_edit_acl": "기여 횟수 총합 50회 이상 가입자만",
+    "tool": "도구",
+    "adsense_enable": "애드센스 사용",
+    "list": "목록",
+    "release": "차단 해제",
+    "category": "분류",
+    "history_delete": "역사 삭제",
+    "markup": "문법",
+    "title": "제목",
+    "edit_tool_list": "편집 도구 목록",
+    "edit_tool_add": "편집 도구 추가",
+    "image_license_list": "이미지 라이선스 목록",
+    "image_license_add": "이미지 라이선스 추가",
+    "direct_input": "직접 입력"
 }
 }

+ 1 - 4
requirements.txt

@@ -3,7 +3,4 @@ bcrypt
 flask
 flask
 flask-Reggie
 flask-Reggie
 flask-compress
 flask-compress
-pysha3; python_version < "3.6"
-css-html-js-minify==2.2.2; python_version < "3.6"
-css-html-js-minify; python_version >= "3.6"
-request
+pysha3; python_version < "3.6"

+ 11 - 0
route/api_markup.py

@@ -0,0 +1,11 @@
+from .tool.func import *
+
+def api_markup_2(conn):
+    curs = conn.cursor()
+
+    curs.execute('select data from other where name = "markup"')
+    rep_data = curs.fetchall()
+    if rep_data[0][0] != '':
+        return flask.jsonify({ "markup" : rep_data[0][0] })
+    else:
+        return flask.jsonify({})

+ 9 - 6
route/api_raw.py

@@ -3,11 +3,14 @@ from .tool.func import *
 def api_raw_2(conn, name):
 def api_raw_2(conn, name):
     curs = conn.cursor()
     curs = conn.cursor()
 
 
-    curs.execute("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)
+    if acl_check(name, 'render') != 1:
+        curs.execute("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)
+        else:
+            return flask.jsonify({})
     else:
     else:
         return flask.jsonify({})
         return flask.jsonify({})

+ 34 - 9
route/api_skin_info.py

@@ -1,15 +1,40 @@
 from .tool.func import *
 from .tool.func import *
 
 
-def api_skin_info_2(conn):
+def api_skin_info_2(conn, name):
     curs = conn.cursor()
     curs = conn.cursor()
 
 
-    json_address = re.sub("(((?!\.|\/).)+)\.html$", "info.json", skin_check())
-    try:
-        json_data = json.loads(open(json_address).read())
-    except:
-        json_data = None
+    if name == '':
+        name = skin_check()
+    else:
+        name = './views/' + name + '/index.html'
+
+    if not flask.request.args.get('all', None):
+        json_address = re.sub("(((?!\.|\/).)+)\.html$", "info.json", name)
+        try:
+            json_data = json.loads(open(json_address).read())
+        except:
+            json_data = None
 
 
-    if json_data:    
-        return flask.jsonify(json_data)
+        if json_data:
+            return flask.jsonify(json_data)
+        else:
+            return flask.jsonify({}), 404
     else:
     else:
-        return flask.jsonify({}), 404
+        a_data = {}
+        for i in load_skin(skin_check(1), 1):
+            json_address = re.sub("(((?!\.|\/).)+)\.html$", "info.json", './views/' + i + '/index.html')
+            try:
+                json_data = json.loads(open(json_address).read())
+            except:
+                json_data = None
+
+            if json_data:
+                if i == skin_check(1):
+                    json_data = {**json_data, **{ "main" : "true" }}
+
+                a_data = {**a_data, **{ i : json_data }}
+
+        if a_data == {}:
+            return flask.jsonify({})
+        else:
+            return flask.jsonify(a_data)

+ 88 - 20
route/api_topic_sub.py

@@ -4,32 +4,100 @@ def api_topic_sub_2(conn, name, sub, time):
     curs = conn.cursor()
     curs = conn.cursor()
 
 
     if flask.request.args.get('num', None):
     if flask.request.args.get('num', None):
-        if flask.request.args.get('over', '0') == '0':
-            curs.execute("select id, data, date, ip from topic where title = ? and sub = ? and id + 0 = ? + 0 order by id + 0 asc", [name, sub, flask.request.args.get('num', '')])
-        elif flask.request.args.get('over', '0') == '1':
-            curs.execute("select id, data, date, ip from topic where title = ? and sub = ? and id + 0 >= ? + 0 order by id + 0 asc", [name, sub, flask.request.args.get('num', '')])
-        else:
-            curs.execute("select id, data, date, ip from topic where title = ? and sub = ? and id + 0 <= ? + 0 order by id + 0 asc", [name, sub, flask.request.args.get('num', '')])
-    elif flask.request.args.get('time', None):
-        if flask.request.args.get('over', '0') == '0':
-            curs.execute("select id, data, date, ip from topic where title = ? and sub = ? and date = ? order by id + 0 asc", [name, sub, flask.request.args.get('time', '')])
-        if flask.request.args.get('over', '0') == '1':
-            curs.execute("select id, data, date, ip from topic where title = ? and sub = ? and date >= ? order by id + 0 asc", [name, sub, flask.request.args.get('time', '')])
-        else:
-            curs.execute("select id, data, date, ip from topic where title = ? and sub = ? and date <= ? order by id + 0 asc", [name, sub, flask.request.args.get('time', '')])
+        curs.execute("select id, data, date, ip, block, top from topic where title = ? and sub = ? and id + 0 = ? + 0 order by id + 0 asc", [
+            name, 
+            sub, 
+            flask.request.args.get('num', '')
+        ])
+    elif flask.request.args.get('top', None):
+        curs.execute("select id, data, date, ip, block, top from topic where title = ? and sub = ? and top = 'O' order by id + 0 asc", [name, sub])
     else:
     else:
-        curs.execute("select id, data, date, ip from topic where title = ? and sub = ? order by id + 0 asc", [name, sub])
+        curs.execute("select id, data, date, ip, block, top from topic where title = ? and sub = ? order by id + 0 asc", [name, sub])
 
 
     data = curs.fetchall()
     data = curs.fetchall()
     if data:
     if data:
         json_data = {}
         json_data = {}
+        admin = admin_check(3)
+                    
         for i in data:
         for i in data:
-            json_data[i[0]] =   {
-                "data" : i[1],
-                "date" : i[2],
-                "id" : i[3]
-            }
+            if i[4] != 'O' or (i[4] == 'O' and admin == 1):
+                t_data_f = i[1]
+                b_color = ''
+            else:
+                curs.execute("select who from re_admin where what = ? order by time desc limit 1", ['blind (' + name + ' - ' + sub + '#' + str(i[0]) + ')'])
+                who_blind = curs.fetchall()
+                if who_blind:
+                    t_data_f = '[[user:' + who_blind[0][0] + ']] block'
+                    b_color = 'toron_color_grey'
+                else:
+                    t_data_f = 'block'
+                    b_color = 'toron_color_grey'
+
+            if flask.request.args.get('render', None):
+                if i[0] == '1':
+                    s_user = i[3]
+                else:
+                    if flask.request.args.get('num', None):
+                        curs.execute("select ip from topic where title = ? and sub = ? order by id + 0 asc limit 1", [name, sub])
+                        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:
+                    t_color = 'toron_color_green'
+                elif i[5] == '1':
+                    t_color = 'toron_color_blue'
+                else:
+                    t_color = 'toron_color'
+                    
+                ip = ip_pas(i[3])
+                
+                curs.execute('select acl from user where id = ?', [i[3]])
+                u_acl = curs.fetchall()
+                if u_acl and u_acl[0][0] != 'user':
+                    ip += ' <a href="javascript:void(0);" title="' + load_lang('admin') + '">★</a>'
+
+                if admin == 1 or b_color != 'toron_color_grey':
+                    ip += ' <a href="/topic/' + url_pas(name) + '/sub/' + url_pas(sub) + '/admin/' + i[0] + '">(' + load_lang('discussion_tool') + ')</a>'
+
+                curs.execute("select end from ban where block = ?", [i[3]])
+                if curs.fetchall():
+                    ip += ' <a href="javascript:void(0);" title="' + load_lang('blocked') + '">†</a>'
+                    
+                if t_data_f == '':
+                    t_data_f = '[br]'
+            
+                all_data = '''
+                    <table id="toron">
+                        <tbody>
+                            <tr>
+                                <td id="''' + t_color + '''">
+                                    <a href="#''' + i[0] + '">#' + i[0] + '</a> ' + ip + ' <span style="float: right;">' + i[2] + '''</span>
+                                </td>
+                            </tr>
+                            <tr>
+                                <td id="''' + b_color + '">' + render_set(data = t_data_f) + '''</td>
+                            </tr>
+                        </tbody>
+                    </table>
+                    <hr class="main_hr">
+                '''
+                
+                json_data[i[0]] = {
+                    "data" : all_data
+                }
+            else:
+                json_data[i[0]] = {
+                    "data" : t_data_f,
+                    "date" : i[2],
+                    "ip" : i[3],
+                    "block" : i[4],
+                }
 
 
         return flask.jsonify(json_data)
         return flask.jsonify(json_data)
     else:
     else:
-        return flask.jsonify({}), 404
+        return flask.jsonify({})

+ 66 - 0
route/api_user_info.py

@@ -0,0 +1,66 @@
+from .tool.func import *
+
+def api_user_info_2(conn, name):
+    curs = conn.cursor()
+
+    if flask.request.args.get('render', None):
+        plus_d = ''
+        plus_t = []
+
+        plus_d = '''
+            <table>
+                <tbody>
+                    <tr>
+                        <td>''' + load_lang('user_name') + '''</td>
+                        <td>{}</td>
+                    </tr>
+                    <tr>
+                        <td>''' + load_lang('authority') + '''</td>
+                        <td>{}</td>
+                    </tr>
+                    <tr>
+                        <td>''' + load_lang('state') + '''</td>
+                        <td>{}</td>
+                    </tr>
+                </tbody>
+            </table>
+        '''
+        
+        curs.execute("select acl from user where id = ?", [name])
+        data = curs.fetchall()
+        if data:
+            if data[0][0] != 'user':
+                plus_t += [data[0][0]]
+            else:
+                plus_t += [load_lang('member')]
+        else:
+            plus_t += [load_lang('normal')]
+
+        if ban_check(name) == 0:
+            plus_t += [load_lang('normal')]
+        else:
+            match = re.search("^([0-9]{1,3}\.[0-9]{1,3})", name)
+            if match:
+                match = match.groups()[0]
+            else:
+                match = '-'
+
+            curs.execute("select end, login, band from ban where block = ? or block = ?", [name, match])
+            block_data = curs.fetchall()
+            if block_data:
+                if block_data[0][0] != '':
+                    plus_t += [load_lang('period') + ' : ' + block_data[0][0]]
+                else:
+                    plus_t += [load_lang('limitless')]
+
+                if block_data[0][1] != '':
+                    plus_t += [load_lang('login_able')]
+
+                if block_data[0][2] == 'O':
+                    plus_t += [load_lang('band_blocked')]
+
+        plus_d = plus_d.format(ip_pas(name), plus_t[0], plus_t[1])
+
+        return flask.jsonify({ "data" : plus_d })
+    else:
+        pass

+ 14 - 11
route/api_w.py

@@ -3,16 +3,19 @@ from .tool.func import *
 def api_w_2(conn, name):
 def api_w_2(conn, name):
     curs = conn.cursor()
     curs = conn.cursor()
 
 
-    if flask.request.method == 'POST':
-        json_data = { "title" : name, "data" : render_set(title = name, data = flask.request.form.get('data', '')) }
-        
-        return flask.jsonify(json_data)
-    else:
-        curs.execute("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]) }
-        
+    if acl_check(name, 'render') != 1:
+        if flask.request.method == 'POST':
+            json_data = { "title" : name, "data" : render_set(title = name, data = flask.request.form.get('data', '')) }
+            
             return flask.jsonify(json_data)
             return flask.jsonify(json_data)
         else:
         else:
-            return flask.jsonify({}), 404
+            curs.execute("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]) }
+            
+                return flask.jsonify(json_data)
+            else:
+                return flask.jsonify({})
+    else:
+        return flask.jsonify({})

+ 17 - 5
route/edit.py

@@ -66,10 +66,22 @@ def edit_2(conn, name):
         new = curs.fetchall()
         new = curs.fetchall()
         if new:
         if new:
             if flask.request.args.get('section', None):
             if flask.request.args.get('section', None):
-                test_data = '\n' + re.sub('\r\n', '\n', new[0][0]) + '\n'   
-                
-                section_data = re.findall('((?:={1,6}) ?(?:(?:(?!={1,6}\n).)+) ?={1,6}\n(?:(?:(?!(?:={1,6}) ?(?:(?:(?!={1,6}\n).)+) ?={1,6}\n).)*\n*)*)', test_data)
-                data = section_data[int(flask.request.args.get('section', '1')) - 1]
+                data = re.sub('\n(?P<in>={1,6})', '<br>\g<in>', html.escape('\n' + re.sub('\r\n', '\n', new[0][0]) + '\n'))
+                i = 0
+
+                while 1:
+                    g_data = re.search('((?:<br>)(?:(?:(?!\n|<br>).)+)(?:\n*(?:(?:(?!<br>).)+\n*)+)?)', data)
+                    if g_data:
+                        if int(flask.request.args.get('section', '1')) - 1 == i:
+                            data = html.unescape(re.sub('<br>(?P<in>={1,6})', '\n\g<in>', g_data.groups()[0]))
+                            
+                            break
+                        else:
+                            data = re.sub('((?:<br>)(?:(?:(?!\n|<br>).)+)(?:\n*(?:(?:(?!<br>).)+\n*)+)?)', '\n', data, 1)
+
+                        i += 1
+                    else:
+                        break
             else:
             else:
                 data = new[0][0]
                 data = new[0][0]
         else:
         else:
@@ -111,7 +123,7 @@ def edit_2(conn, name):
                     <hr class=\"main_hr\">
                     <hr class=\"main_hr\">
                     ''' + captcha_get() + ip_warring() + '''
                     ''' + captcha_get() + ip_warring() + '''
                     <button id="save" type="submit">''' + load_lang('save') + '''</button>
                     <button id="save" type="submit">''' + load_lang('save') + '''</button>
-                    <button id="preview" type="button" onclick="do_preview(\'''' + name + '\')">' + load_lang('preview') + '''</button>
+                    <button id="preview" type="button" onclick="load_preview(\'''' + name + '\')">' + load_lang('preview') + '''</button>
                 </form>
                 </form>
                 ''' + b_text + '''
                 ''' + b_text + '''
                 <hr class=\"main_hr\">
                 <hr class=\"main_hr\">

+ 44 - 9
route/func_upload.py

@@ -47,13 +47,22 @@ def func_upload_2(conn):
             
             
         ip = ip_check()
         ip = ip_check()
 
 
-        if flask.request.form.get('f_lice', None):
-            lice = flask.request.form.get('f_lice', None)
-        else:
-            if custom()[2] == 0:
-                lice = ip
+        if flask.request.form.get('f_lice_sel', 'direct_input') == 'direct_input':
+            if flask.request.form.get('f_lice', None):
+                lice = flask.request.form.get('f_lice', None)
             else:
             else:
-                lice = '[[user:' + ip + ']]'
+                if custom()[2] == 0:
+                    lice = ip
+                else:
+                    lice = '[[user:' + ip + ']]'
+
+            lice += '[[category:direct_input]]'
+        else:
+            lice = flask.request.form.get('f_lice_sel', None)
+            if flask.request.form.get('f_lice', None):
+                lice += ' : '  + flask.request.form.get('f_lice', None)
+
+            lice += '[[category:' + re.sub('\]', '_', flask.request.form.get('f_lice_sel', None)) + ']]'
             
             
         if os.path.exists(os.path.join(app_var['path_data_image'], e_data)):
         if os.path.exists(os.path.join(app_var['path_data_image'], e_data)):
             os.remove(os.path.join(app_var['path_data_image'], e_data))
             os.remove(os.path.join(app_var['path_data_image'], e_data))
@@ -61,12 +70,21 @@ def func_upload_2(conn):
             data.save(os.path.join(app_var['path_data_image'], e_data))
             data.save(os.path.join(app_var['path_data_image'], e_data))
         else:
         else:
             data.save(os.path.join(app_var['path_data_image'], e_data))
             data.save(os.path.join(app_var['path_data_image'], e_data))
+
+        file_d = '[[file:' + name + ']][br][br]{{{[[file:' + name + ']]}}}[br][br]' + lice
         
         
-        curs.execute("insert into data (title, data) values (?, ?)", ['file:' + name, '[[file:' + name + ']][br][br]{{{[[file:' + name + ']]}}}[br][br]' + lice])
-        curs.execute("insert into acl (title, dec, dis, why, view) values (?, 'admin', '', '', '')", ['file:' + name])
+        curs.execute("insert into data (title, data) values (?, ?)", ['file:' + name, file_d])
+        curs.execute("insert into acl (title, decu, dis, why, view) values (?, 'admin', '', '', '')", ['file:' + name])
+
+        render_set(
+            title = name,
+            data = file_d,
+            num = 1
+        )
 
 
         history_plus(
         history_plus(
-            'file:' + name, '[[file:' + name + ']][br][br]{{{[[file:' + name + ']]}}}[br][br]' + lice,
+            'file:' + name,
+            file_d,
             get_time(), 
             get_time(), 
             ip, 
             ip, 
             '(upload)',
             '(upload)',
@@ -77,16 +95,33 @@ def func_upload_2(conn):
         
         
         return redirect('/w/file:' + name)      
         return redirect('/w/file:' + name)      
     else:
     else:
+        license_list = '''
+            <option value="direct_input">''' + load_lang('direct_input') + '''</option>
+        '''
+
+        curs.execute("select html from html_filter where kind = 'image_license'")
+        db_data = curs.fetchall()
+        for i in db_data:
+            license_list += '''
+                <option value="''' + i[0] + '''">''' + i[0] + '''</option>
+            '''
+
         return easy_minify(flask.render_template(skin_check(), 
         return easy_minify(flask.render_template(skin_check(), 
             imp = [load_lang('upload'), wiki_set(), custom(), other2([0, 0])],
             imp = [load_lang('upload'), wiki_set(), custom(), other2([0, 0])],
             data =  '''
             data =  '''
                 <a href="/file_filter">(''' + load_lang('file_filter_list') + ''')</a>
                 <a href="/file_filter">(''' + load_lang('file_filter_list') + ''')</a>
                 <hr class=\"main_hr\">
                 <hr class=\"main_hr\">
+                ''' + load_lang('max_file_size') + ''' : ''' + wiki_set(3) + '''MB
+                <hr class=\"main_hr\">
                 <form method="post" enctype="multipart/form-data" accept-charset="utf8">
                 <form method="post" enctype="multipart/form-data" accept-charset="utf8">
                     <input type="file" name="f_data">
                     <input type="file" name="f_data">
                     <hr class=\"main_hr\">
                     <hr class=\"main_hr\">
                     <input placeholder="''' + load_lang('file_name') + '''" name="f_name" type="text">
                     <input placeholder="''' + load_lang('file_name') + '''" name="f_name" type="text">
                     <hr class=\"main_hr\">
                     <hr class=\"main_hr\">
+                    <select name="f_lice_sel">
+                        ''' + license_list + '''
+                    </select>
+                    <hr class=\"main_hr\">
                     <input placeholder="''' + load_lang('license') + '''" name="f_lice" type="text">
                     <input placeholder="''' + load_lang('license') + '''" name="f_lice" type="text">
                     <hr class=\"main_hr\">
                     <hr class=\"main_hr\">
                     ''' + captcha_get() + '''
                     ''' + captcha_get() + '''

+ 8 - 8
route/give_acl.py

@@ -29,25 +29,25 @@ def give_acl_2(conn, name):
                 check_ok = 'disabled'
                 check_ok = 'disabled'
 
 
     if flask.request.method == 'POST':
     if flask.request.method == 'POST':
-        dec = flask.request.form.get('dec', '')
+        decu = flask.request.form.get('decu', '')
         view = flask.request.form.get('view', '')
         view = flask.request.form.get('view', '')
 
 
         curs.execute("select title from acl where title = ?", [name])
         curs.execute("select title from acl where title = ?", [name])
         if curs.fetchall():
         if curs.fetchall():
-            curs.execute("update acl set dec = ? where title = ?", [dec, name])
+            curs.execute("update acl set decu = ? where title = ?", [decu, name])
             curs.execute("update acl set dis = ? where title = ?", [flask.request.form.get('dis', ''), name])
             curs.execute("update acl set dis = ? where title = ?", [flask.request.form.get('dis', ''), name])
             curs.execute("update acl set why = ? where title = ?", [flask.request.form.get('why', ''), name])
             curs.execute("update acl set why = ? where title = ?", [flask.request.form.get('why', ''), name])
             curs.execute("update acl set view = ? where title = ?", [view, name])
             curs.execute("update acl set view = ? where title = ?", [view, name])
         else:
         else:
-            curs.execute("insert into acl (title, dec, dis, why, view) values (?, ?, ?, ?, ?)", [
+            curs.execute("insert into acl (title, decu, dis, why, view) values (?, ?, ?, ?, ?)", [
                 name, 
                 name, 
-                dec, 
+                decu, 
                 flask.request.form.get('dis', ''), 
                 flask.request.form.get('dis', ''), 
                 flask.request.form.get('why', ''), 
                 flask.request.form.get('why', ''), 
                 view
                 view
             ])
             ])
         
         
-        curs.execute("select title from acl where title = ? and dec = '' and dis = '' and view = ''", [name])
+        curs.execute("select title from acl where title = ? and decu = '' and dis = '' and view = ''", [name])
         if curs.fetchall():
         if curs.fetchall():
             curs.execute("delete from acl where title = ?", [name])
             curs.execute("delete from acl where title = ?", [name])
 
 
@@ -55,14 +55,14 @@ def give_acl_2(conn, name):
             
             
         return redirect('/acl/' + url_pas(name))            
         return redirect('/acl/' + url_pas(name))            
     else:
     else:
-        data = '<h2>' + load_lang('document_acl') + '</h2><hr class=\"main_hr\"><select name="dec" ' + check_ok + '>'
+        data = '<h2>' + load_lang('document_acl') + '</h2><hr class=\"main_hr\"><select name="decu" ' + check_ok + '>'
     
     
         if re.search('^user:', name):
         if re.search('^user:', name):
             acl_list = [['', 'normal'], ['user', 'member'], ['all', 'all']]
             acl_list = [['', 'normal'], ['user', 'member'], ['all', 'all']]
         else:
         else:
             acl_list = [['', 'normal'], ['user', 'member'], ['admin', 'admin'], ['50_edit', '50 edit'], ['email', 'email']]
             acl_list = [['', 'normal'], ['user', 'member'], ['admin', 'admin'], ['50_edit', '50 edit'], ['email', 'email']]
         
         
-        curs.execute("select dec from acl where title = ?", [name])
+        curs.execute("select decu from acl where title = ?", [name])
         acl_data = curs.fetchall()
         acl_data = curs.fetchall()
         for data_list in acl_list:
         for data_list in acl_list:
             if acl_data and acl_data[0][0] == data_list[0]:
             if acl_data and acl_data[0][0] == data_list[0]:
@@ -107,7 +107,7 @@ def give_acl_2(conn, name):
                     <li>member : ''' + load_lang('member_acl') + '''</li>
                     <li>member : ''' + load_lang('member_acl') + '''</li>
                     <li>50 edit : ''' + load_lang('50_edit_acl') + '''</li>
                     <li>50 edit : ''' + load_lang('50_edit_acl') + '''</li>
                     <li>all : ''' + load_lang('all_acl') + '''</li>
                     <li>all : ''' + load_lang('all_acl') + '''</li>
-                    <li>all : ''' + load_lang('email_acl') + '''</li>
+                    <li>email : ''' + load_lang('email_acl') + '''</li>
                 </ul>
                 </ul>
             '''
             '''
                 
                 

+ 0 - 1
route/give_user_ban.py

@@ -106,7 +106,6 @@ def give_user_ban_2(conn, name):
             insert_data = ''
             insert_data = ''
             for i in time_data:
             for i in time_data:
                 insert_data += '<a href="javascript:insert_v(\'second\', \'' + i[0] + '\')">(' + i[1] + ')</a> '
                 insert_data += '<a href="javascript:insert_v(\'second\', \'' + i[0] + '\')">(' + i[1] + ')</a> '
-            # 언어 적용 필요
 
 
             data = name + '''
             data = name + '''
                 <script>function insert_v(name, data) { document.getElementById(name).value = data; }</script>''' + insert_data + '''                
                 <script>function insert_v(name, data) { document.getElementById(name).value = data; }</script>''' + insert_data + '''                

+ 25 - 1
route/inter_wiki.py

@@ -42,13 +42,34 @@ def inter_wiki_2(conn, tools):
         div = ''
         div = ''
 
 
         curs.execute("select name from filter")
         curs.execute("select name from filter")
-    else:
+    elif tools == 'file_filter':
         del_link = 'del_file_filter'
         del_link = 'del_file_filter'
         plus_link = 'plus_file_filter'
         plus_link = 'plus_file_filter'
         title = load_lang('file_filter_list')
         title = load_lang('file_filter_list')
         div = ''
         div = ''
 
 
         curs.execute("select html from html_filter where kind = 'file'")
         curs.execute("select html from html_filter where kind = 'file'")
+    elif tools == 'file_filter':
+        del_link = 'del_file_filter'
+        plus_link = 'plus_file_filter'
+        title = load_lang('file_filter_list')
+        div = ''
+
+        curs.execute("select html from html_filter where kind = 'file'")  
+    elif tools == 'image_license':
+        del_link = 'del_image_license'
+        plus_link = 'plus_image_license'
+        title = load_lang('image_license_list')
+        div = ''
+
+        curs.execute("select html from html_filter where kind = 'image_license'")  
+    else:
+        del_link = 'del_edit_top'
+        plus_link = 'plus_edit_top'
+        title = load_lang('edit_tool_list')
+        div = ''
+
+        curs.execute("select html, plus from html_filter where kind = 'edit_top'")
 
 
     db_data = curs.fetchall()
     db_data = curs.fetchall()
     if db_data:
     if db_data:
@@ -62,6 +83,9 @@ def inter_wiki_2(conn, tools):
             else:
             else:
                 div += '<li>' + data[0]
                 div += '<li>' + data[0]
 
 
+                if tools == 'edit_top':
+                    div += ' : ' + data[1]
+
             if admin == 1:
             if admin == 1:
                 div += ' <a href="/' + del_link + '/' + url_pas(data[0]) + '">(' + load_lang('delete') + ')</a>'
                 div += ' <a href="/' + del_link + '/' + url_pas(data[0]) + '">(' + load_lang('delete') + ')</a>'
 
 

+ 5 - 1
route/inter_wiki_del.py

@@ -12,8 +12,12 @@ def inter_wiki_del_2(conn, tools, name):
             curs.execute("delete from html_filter where html = ? and kind = 'name'", [name])
             curs.execute("delete from html_filter where html = ? and kind = 'name'", [name])
         elif tools == 'del_file_filter':
         elif tools == 'del_file_filter':
             curs.execute("delete from html_filter where html = ? and kind = 'file'", [name])
             curs.execute("delete from html_filter where html = ? and kind = 'file'", [name])
-        else:
+        elif tools == 'del_email_filter':
             curs.execute("delete from html_filter where html = ? and kind = 'email'", [name])
             curs.execute("delete from html_filter where html = ? and kind = 'email'", [name])
+        elif tools == 'del_image_license':
+            curs.execute("delete from html_filter where html = ? and kind = 'image_license'", [name])    
+        else:
+            curs.execute("delete from html_filter where html = ? and kind = 'edit_top'", [name])
         
         
         conn.commit()
         conn.commit()
 
 

+ 25 - 5
route/inter_wiki_plus.py

@@ -28,6 +28,8 @@ def inter_wiki_plus_2(conn, tools, name):
             except:
             except:
                 return re_error('/error/23')                
                 return re_error('/error/23')                
         else:
         else:
+            plus_d = ''
+
             if tools == 'plus_name_filter':
             if tools == 'plus_name_filter':
                 try:
                 try:
                     re.compile(flask.request.form.get('title', 'test'))
                     re.compile(flask.request.form.get('title', 'test'))
@@ -46,12 +48,21 @@ def inter_wiki_plus_2(conn, tools, name):
                 admin_check(None, 'file_filter edit')
                 admin_check(None, 'file_filter edit')
                 
                 
                 type_d = 'file'
                 type_d = 'file'
-            else:
+            elif tools == 'plus_email_filter':
                 admin_check(None, 'email_filter edit')
                 admin_check(None, 'email_filter edit')
                 
                 
                 type_d = 'email'
                 type_d = 'email'
+            elif tools == 'plus_image_license':
+                admin_check(None, 'image_license edit')
+                
+                type_d = 'image_license'
+            else:
+                admin_check(None, 'edit_top edit')
+                
+                type_d = 'edit_top'
+                plus_d = flask.request.form.get('markup', 'test')
             
             
-            curs.execute('insert into html_filter (html, kind) values (?, ?)', [flask.request.form.get('title', 'test'), type_d])
+            curs.execute('insert into html_filter (html, kind, plus) values (?, ?, ?)', [flask.request.form.get('title', 'test'), type_d, plus_d])
         
         
         conn.commit()
         conn.commit()
     
     
@@ -112,10 +123,19 @@ def inter_wiki_plus_2(conn, tools, name):
         elif tools == 'plus_file_filter':
         elif tools == 'plus_file_filter':
             title = load_lang('file_filter_add')
             title = load_lang('file_filter_add')
             form_data = '<input placeholder="' + load_lang('regex') + '" type="text" name="title">'
             form_data = '<input placeholder="' + load_lang('regex') + '" type="text" name="title">'
-        else:
+        elif tools == 'plus_email_filter':
             title = load_lang('email_filter_add')
             title = load_lang('email_filter_add')
-            form_data = '<input placeholder="email" type="text" name="title">'
-
+            form_data = '<input placeholder="' + load_lang('email') + '" type="text" name="title">'
+        elif tools == 'plus_image_license':
+            title = load_lang('image_license_add')
+            form_data = '<input placeholder="' + load_lang('license') + '" type="text" name="title">'
+        else:
+            title = load_lang('edit_tool_add')
+            form_data = '''
+                <input placeholder="''' + load_lang('title') + '''" type="text" name="title">
+                <hr class=\"main_hr\">
+                <input placeholder="''' + load_lang('markup') + '''" type="text" name="markup">
+            '''
 
 
         return easy_minify(flask.render_template(skin_check(), 
         return easy_minify(flask.render_template(skin_check(), 
             imp = [title, wiki_set(), custom(), other2([0, 0])],
             imp = [title, wiki_set(), custom(), other2([0, 0])],

+ 1 - 1
route/list_acl.py

@@ -13,7 +13,7 @@ def list_acl_2(conn):
                     <td id="main_table_width_quarter">''' + load_lang('view_acl') + '''</td>
                     <td id="main_table_width_quarter">''' + load_lang('view_acl') + '''</td>
     '''
     '''
     
     
-    curs.execute("select title, dec, dis, view, why from acl where dec != '' or dis != '' or view != '' order by title desc")
+    curs.execute("select title, decu, dis, view, why from acl where decu != '' or dis != '' or view != '' order by title desc")
     list_data = curs.fetchall()
     list_data = curs.fetchall()
     for data in list_data:
     for data in list_data:
         if not re.search('^user:', data[0]) and not re.search('^file:', data[0]):
         if not re.search('^user:', data[0]) and not re.search('^file:', data[0]):

+ 1 - 0
route/list_admin_use.py

@@ -35,6 +35,7 @@ def list_admin_use_2(conn):
                 <form method="post">
                 <form method="post">
                     <input name="search" id="admin_log_search"> <button type="submit">''' + load_lang('search') + '''</button>
                     <input name="search" id="admin_log_search"> <button type="submit">''' + load_lang('search') + '''</button>
                 </form>
                 </form>
+                <hr class=\"main_hr\">
             ''' + list_data,
             ''' + list_data,
             menu = [['other', load_lang('return')]]
             menu = [['other', load_lang('return')]]
         ))
         ))

+ 3 - 0
route/main_manager.py

@@ -42,6 +42,8 @@ def main_manager_2(conn, num, r_ver):
                     <h3>''' + load_lang('filter') + '''</h3>
                     <h3>''' + load_lang('filter') + '''</h3>
                     <ul>
                     <ul>
                         <li><a href="/inter_wiki">''' + load_lang('interwiki_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>
+                        <li><a href="/image_license">''' + load_lang('image_license_list') + '''</a></li>
                         <li><a href="/email_filter">''' + load_lang('email_filter_list') + '''</a></li>
                         <li><a href="/email_filter">''' + load_lang('email_filter_list') + '''</a></li>
                         <li><a href="/name_filter">''' + load_lang('id_filter_list') + '''</a></li>
                         <li><a href="/name_filter">''' + load_lang('id_filter_list') + '''</a></li>
                         <li><a href="/file_filter">''' + load_lang('file_filter_list') + '''</a></li>
                         <li><a href="/file_filter">''' + load_lang('file_filter_list') + '''</a></li>
@@ -58,6 +60,7 @@ def main_manager_2(conn, num, r_ver):
                     <br>
                     <br>
                     <h2>''' + load_lang('version') + '''</h2>
                     <h2>''' + load_lang('version') + '''</h2>
                     <ul>
                     <ul>
+                        <li><a href="/api/skin_info?all=true">''' + load_lang('skin_info') + '''</a></li>
                         <li>''' + load_lang('version') + ' : ' + r_ver + '''</li>
                         <li>''' + load_lang('version') + ' : ' + r_ver + '''</li>
                         <li id="ver_send" style="display: none;">''' + load_lang('lastest') + ''' : </li>
                         <li id="ver_send" style="display: none;">''' + load_lang('lastest') + ''' : </li>
                     </ul>
                     </ul>

+ 29 - 20
route/main_views.py

@@ -3,30 +3,39 @@ from .tool.func import *
 def main_views_2(conn, name):
 def main_views_2(conn, name):
     curs = conn.cursor()
     curs = conn.cursor()
 
 
-    if re.search('\/', name):
-        m = re.search('^(.*)\/(.*)$', name)
-        if m:
-            n = m.groups()
-            plus = '/' + n[0]
-            rename = n[1]
-        else:
-            plus = ''
-            rename = name
-    else:
-        plus = ''
-        rename = name
-
-    m = re.search('\.(.+)$', name)
+    m = re.search('\.([^.]+)$', name)
     if m:
     if m:
         g = m.groups()
         g = m.groups()
     else:
     else:
         g = ['']
         g = ['']
 
 
-    if g == 'css':
-        return easy_minify(flask.send_from_directory('./views' + plus, rename), 'css')   
-    elif g == 'js':
-        return easy_minify(flask.send_from_directory('./views' + plus, rename), 'js')
-    elif g == 'html':
-        return easy_minify(flask.send_from_directory('./views' + plus, rename))   
+    if g[0] == 'css':
+        c_open = open('./views/' + name, encoding='utf-8')
+        f_open = c_open.read()
+        c_open.close()
+        return flask.Response(easy_minify(f_open, 'css'), mimetype="text/css")
+    elif g[0] == 'js':
+        c_open = open('./views/' + name, encoding='utf-8')
+        f_open = c_open.read()
+        c_open.close()
+        return flask.Response(easy_minify(f_open, 'js'), mimetype="text/js")
+    elif g[0] == 'html':
+        c_open = open('./views/' + name, encoding='utf-8')
+        f_open = c_open.read()
+        c_open.close()
+        return flask.Response(easy_minify(f_open), mimetype="text/html")
     else:
     else:
+        if re.search('\/', name):
+            m = re.search('^(.*)\/(.*)$', name)
+            if m:
+                n = m.groups()
+                plus = '/' + n[0]
+                rename = n[1]
+            else:
+                plus = ''
+                rename = name
+        else:
+            plus = ''
+            rename = name
+
         return flask.send_from_directory('./views' + plus, rename)
         return flask.send_from_directory('./views' + plus, rename)

+ 5 - 15
route/recent_changes.py

@@ -119,11 +119,7 @@ def recent_changes_2(conn, name, tool):
                 leng = '<span style="color:gray;">(' + data[5] + ')</span>'
                 leng = '<span style="color:gray;">(' + data[5] + ')</span>'
                 
                 
             ip = ip_pas(data[3])
             ip = ip_pas(data[3])
-            if int(data[0]) - 1 == 0:
-                revert = ''
-            else:
-                revert = '<a href="/diff/' + url_pas(data[1]) + '?first=' + str(int(data[0]) - 1) + '&second=' + data[0] + '">(' + load_lang('compare') + ')</a>'
-                revert += ' <a href="/revert/' + url_pas(data[1]) + '?num=' + str(int(data[0]) - 1) + '">(' + load_lang('revert') + ')</a>'
+            m_tool = '<a href="/history_tool/' + url_pas(data[1]) + '?num=' + data[0] + '">(' + load_lang('tool') + ')</a>'
             
             
             style = ['', '']
             style = ['', '']
             date = data[2]
             date = data[2]
@@ -135,9 +131,7 @@ def recent_changes_2(conn, name, tool):
             hide = curs.fetchall()
             hide = curs.fetchall()
             
             
             if six_admin == 1:
             if six_admin == 1:
-                if hide:                            
-                    hidden = ' <a href="/hidden/' + url_pas(data[1]) + '?num=' + data[0] + '">(' + load_lang('hide_release') + ')'
-                    
+                if hide:                    
                     style[0] = 'id="toron_color_grey"'
                     style[0] = 'id="toron_color_grey"'
                     style[1] = 'id="toron_color_grey"'
                     style[1] = 'id="toron_color_grey"'
                     
                     
@@ -145,13 +139,10 @@ def recent_changes_2(conn, name, tool):
                         send = '(' + load_lang('hide') + ')'
                         send = '(' + load_lang('hide') + ')'
                     else:
                     else:
                         send += ' (' + load_lang('hide') + ')'
                         send += ' (' + load_lang('hide') + ')'
-                else:
-                    hidden = ' <a href="/hidden/' + url_pas(data[1]) + '?num=' + data[0] + '">(' + load_lang('hide') + ')'
             elif not hide:
             elif not hide:
-                hidden = ''
+                pass
             else:
             else:
                 ip = ''
                 ip = ''
-                hidden = ''
                 ban = ''
                 ban = ''
                 date = ''
                 date = ''
 
 
@@ -162,15 +153,14 @@ def recent_changes_2(conn, name, tool):
 
 
             if tool == 'history':
             if tool == 'history':
                 title = '<a href="/w/' + url_pas(name) + '?num=' + data[0] + '">r' + data[0] + '</a> '
                 title = '<a href="/w/' + url_pas(name) + '?num=' + data[0] + '">r' + data[0] + '</a> '
-                title += '<a href="/raw/' + url_pas(name) + '?num=' + data[0] + '">(' + load_lang('raw') + ')</a> '
             else:
             else:
                 title = '<a href="/w/' + url_pas(data[1]) + '">' + html.escape(data[1]) + '</a> '
                 title = '<a href="/w/' + url_pas(data[1]) + '">' + html.escape(data[1]) + '</a> '
                 title += '<a href="/history/' + url_pas(data[1]) + '">(r' + data[0] + ')</a> '
                 title += '<a href="/history/' + url_pas(data[1]) + '">(r' + data[0] + ')</a> '
 
 
             div +=  '''
             div +=  '''
                 <tr ''' + style[0] + '''>
                 <tr ''' + style[0] + '''>
-                    <td>''' + title + revert + ' ' + leng + '''</td>
-                    <td>''' + ip + ban + hidden + '''</td>
+                    <td>''' + title + m_tool + ' ' + leng + '''</td>
+                    <td>''' + ip + ban + '''</td>
                     <td>''' + date + '''</td>
                     <td>''' + date + '''</td>
                 </tr>
                 </tr>
                 <tr ''' + style[1] + '''>
                 <tr ''' + style[1] + '''>

+ 27 - 0
route/recent_history_delete.py

@@ -0,0 +1,27 @@
+from .tool.func import *
+
+def recent_history_delete_2(conn, name):
+    curs = conn.cursor()
+
+    num = str(int(number_check(flask.request.args.get('num', '1'))))
+
+    if admin_check() != 1:
+        return re_error('/error/3')
+
+    if flask.request.method == 'POST':
+        admin_check(None, 'history delete r' + num)
+
+        curs.execute("delete from history where id = ? and title = ?", [num, name])
+        conn.commit()
+
+        return redirect('/history/' + url_pas(name))
+    else:
+        return easy_minify(flask.render_template(skin_check(), 
+            imp = [name, wiki_set(), custom(), other2(['(r' + num + ')', 0])],
+            data = '''
+                <form method="post">
+                    <button type="submit">''' + load_lang('history_delete') + '''</button>
+                </form>
+            ''',
+            menu = [['history/' + url_pas(name), load_lang('return')]]
+        ))

+ 53 - 0
route/recent_history_tool.py

@@ -0,0 +1,53 @@
+from .tool.func import *
+
+def recent_history_tool_2(conn, name):
+    curs = conn.cursor()
+
+    num = str(int(number_check(flask.request.args.get('num', '1'))))
+
+    data = '''
+        <h2>''' + load_lang('tool') + '''</h2>
+        <ul>
+            <li>
+                <a href="/raw/''' + url_pas(name) + '?num=' + num + '">' + load_lang('raw') + '''</a> 
+            </li>
+    '''
+
+    if (int(num) - 1) > 0:
+        data += '''
+            <li>
+                <a href="/diff/''' + url_pas(name) + '?first=''' + str(int(num) - 1) + '&second=' + num + '">' + load_lang('compare') + '''</a>
+            </li>
+            <li>
+                <a href="/revert/''' + url_pas(name) + '?num=' + str(int(num) - 1) + '">' + load_lang('revert') + '''</a>
+            </li>
+        '''
+
+    if admin_check(6) == 1:
+        curs.execute('''
+            select title from history
+            where title = ? and id = ? and hide = 'O'
+        ''', [name, num])
+        hide = curs.fetchall()
+        data += '''
+            <li>
+                <a href="/hidden/''' + url_pas(name) + '?num=' + num + '">' + (load_lang('hide_release') if hide else load_lang('hide')) + '''
+            </li>
+        '''
+
+    if admin_check() == 1:
+        data += '''
+            <li>
+                <a href="/history_delete/''' + url_pas(name) + '?num=' + num + '">' + load_lang('history_delete') + '''
+            </li>
+        '''
+
+    data += '''
+        </ul>
+    '''
+                
+    return easy_minify(flask.render_template(skin_check(), 
+        imp = [name, wiki_set(), custom(), other2(['(r' + num + ')', 0])],
+        data = data,
+        menu = [['history/' + url_pas(name), load_lang('return')]]
+    ))

+ 13 - 3
route/setting.py

@@ -189,7 +189,7 @@ def setting_2(conn, num):
                         <hr class=\"main_hr\">
                         <hr class=\"main_hr\">
                         <input type="checkbox" name="ip_view" ''' + ch_2 + '''> ''' + load_lang('hide_ip') + '''
                         <input type="checkbox" name="ip_view" ''' + ch_2 + '''> ''' + load_lang('hide_ip') + '''
                         <hr class=\"main_hr\">
                         <hr class=\"main_hr\">
-                        <input type="checkbox" name="email_have" ''' + ch_3 + '''> ''' + load_lang('email_required') + ''' {<a href="/setting/5">''' + load_lang('google_imap_required') + '''</a>}
+                        <input type="checkbox" name="email_have" ''' + ch_3 + '''> ''' + load_lang('email_required') + ''' {<a href="/setting/6">''' + load_lang('google_imap_required') + '''</a>}
                         <hr class=\"main_hr\">
                         <hr class=\"main_hr\">
                         <span>''' + load_lang('wiki_host') + '''</span>
                         <span>''' + load_lang('wiki_host') + '''</span>
                         <hr class=\"main_hr\">
                         <hr class=\"main_hr\">
@@ -226,7 +226,9 @@ def setting_2(conn, num):
             'email_text',
             'email_text',
             'email_insert_text',
             'email_insert_text',
             'password_search_text',
             'password_search_text',
-            'reset_user_text'
+            'reset_user_text',
+            'error_401',
+            'error_404'
         ]
         ]
         if flask.request.method == 'POST':
         if flask.request.method == 'POST':
             for i in i_list:
             for i in i_list:
@@ -295,6 +297,14 @@ def setting_2(conn, num):
                         <hr class=\"main_hr\">
                         <hr class=\"main_hr\">
                         <input name="''' + i_list[8] + '''" value="''' + html.escape(d_list[8]) + '''">
                         <input name="''' + i_list[8] + '''" value="''' + html.escape(d_list[8]) + '''">
                         <hr class=\"main_hr\">
                         <hr class=\"main_hr\">
+                        <span>''' + load_lang('error_401') + '''</span>
+                        <hr class=\"main_hr\">
+                        <input name="''' + i_list[9] + '''" value="''' + html.escape(d_list[9]) + '''">
+                        <hr class=\"main_hr\">
+                        <span>''' + load_lang('error_404') + '''</span>
+                        <hr class=\"main_hr\">
+                        <input name="''' + i_list[10] + '''" value="''' + html.escape(d_list[10]) + '''">
+                        <hr class=\"main_hr\">
                         <button id="save" type="submit">''' + load_lang('save') + '''</button>
                         <button id="save" type="submit">''' + load_lang('save') + '''</button>
                     </form>
                     </form>
                 ''',
                 ''',
@@ -477,4 +487,4 @@ def setting_2(conn, num):
                 menu = [['setting', load_lang('return')]]
                 menu = [['setting', load_lang('return')]]
             ))
             ))
     else:
     else:
-        return redirect()
+        return redirect()

+ 5 - 4
route/setting_adsense.py

@@ -43,19 +43,20 @@ def setting_adsense_2(conn):
                     {}
                     {}
                 </label>
                 </label>
             </div>
             </div>
-            <hr>
+            <hr class=\"main_hr\">
             <div class="form-group">
             <div class="form-group">
                 <textarea class="form-control" id="adsense_code" name="adsense_code" rows="12">{}</textarea>
                 <textarea class="form-control" id="adsense_code" name="adsense_code" rows="12">{}</textarea>
             </div>
             </div>
+            <hr class=\"main_hr\">
             <button type="submit" value="publish">{}</button>
             <button type="submit" value="publish">{}</button>
         </form>
         </form>
     '''
     '''
     
     
     body_content += template.format(
     body_content += template.format(
-        'checked' if adsense_enabled == 'True' else template.format(''),
+        'checked' if adsense_enabled == 'True' else '',
         load_lang('adsense_enable'),
         load_lang('adsense_enable'),
-        load_lang('save'),
-        adsense_code
+        adsense_code,
+        load_lang('save')
     )
     )
 
 
     return easy_minify(flask.render_template(skin_check(),
     return easy_minify(flask.render_template(skin_check(),

+ 28 - 75
route/tool/func.py

@@ -20,7 +20,6 @@ for i in range(0, 2):
         import zipfile
         import zipfile
         import difflib
         import difflib
         import shutil
         import shutil
-        import request
         import threading
         import threading
         import logging
         import logging
         import random
         import random
@@ -29,11 +28,6 @@ for i in range(0, 2):
         import html
         import html
         import re
         import re
 
 
-        try:
-            import css_html_js_minify
-        except:
-            pass
-
         if sys.version_info < (3, 6):
         if sys.version_info < (3, 6):
             import sha3
             import sha3
 
 
@@ -41,6 +35,8 @@ for i in range(0, 2):
         from .mark import *
         from .mark import *
     except ImportError as e:
     except ImportError as e:
         if i == 0:
         if i == 0:
+            print(e)
+            print('----')
             if platform.system() == 'Linux':
             if platform.system() == 'Linux':
                 ok = os.system('python3 -m pip install --user -r requirements.txt')
                 ok = os.system('python3 -m pip install --user -r requirements.txt')
                 if ok == 0:
                 if ok == 0:
@@ -64,7 +60,7 @@ for i in range(0, 2):
             print(e)
             print(e)
             raise
             raise
 
 
-app_var = json.loads(open('data/app_variables.json', encoding='utf-8').read())
+app_var = json.loads(open('data/app_var.json', encoding='utf-8').read())
 
 
 def load_conn(data):
 def load_conn(data):
     global conn
     global conn
@@ -135,19 +131,7 @@ def last_change(data):
 
 
     return data
     return data
 
 
-def easy_minify(data, tool = None):
-    try:
-        if not tool:
-            data = css_html_js_minify.html_minify(data)
-        else:
-            if tool == 'css':
-                data = css_html_js_minify.css_minify(data)
-            elif tool == 'js':
-                data = css_html_js_minify.js_minify(data)
-    except:
-        data = re.sub('\n +<', '\n<', data)
-        data = re.sub('>(\n| )+<', '> <', data)
-    
+def easy_minify(data, tool = None):    
     return last_change(data)
     return last_change(data)
 
 
 def render_set(title = '', data = '', num = 0, s_data = 0):
 def render_set(title = '', data = '', num = 0, s_data = 0):
@@ -176,55 +160,19 @@ def captcha_get():
     return data
     return data
 
 
 def update():
 def update():
-    # v3.0.8 rd, agreedis, stop 테이블 통합
+    #v3.1.2
     try:
     try:
-        curs.execute("select title, sub, close from stop")
-        for i in curs.fetchall():
-            if i[2] == '':
-                curs.execute("update rd set stop = 'S' where title = ? and sub = ?", [i[0], i[1]])
-            else:
-                curs.execute("update rd set stop = 'O' where title = ? and sub = ?", [i[0], i[1]])
-    except:
-        pass
-        
-    try:
-        curs.execute("select title, sub from agreedis")
-        for i in curs.fetchall():
-            curs.execute("update rd set agree = 'O' where title = ? and sub = ?", [i[0], i[1]])
-    except:
-        pass
-         
-    try:
-        curs.execute("drop table if exists stop")
-        curs.execute("drop table if exists agreedis")
+        curs.execute('select title, dec from acl where dec != ""')
+        db_data = curs.fetchall()
+        for i in db_data:
+            curs.execute("update acl set decu = ? where title = ?", [i[1], i[0]])
+
+        print('fix table acl column dec to decu')
+        print('----')
     except:
     except:
         pass
         pass
 
 
-    # Start : Data migration code
-    app_var = json.loads(open(os.path.abspath('./data/app_variables.json'), encoding='utf-8').read())
-
-    if os.path.exists('image'):
-        os.rename('image', app_var['path_data_image'])
-
-    if os.path.exists('oauthsettings.json'):
-        os.rename('oauthsettings.json', app_var['path_oauth_setting'])
-
-    try:
-        load_oauth('discord')
-    except KeyError:
-        old_oauth_data = json.loads(open(app_var['path_oauth_setting'], encoding='utf-8').read())
-
-        if 'discord' not in old_oauth_data['_README']['support']:
-            old_oauth_data['_README']['support'] += ['discord']
-
-        old_oauth_data['discord'] = {}
-        old_oauth_data['discord']['client_id'] = ''
-        old_oauth_data['discord']['client_secret'] = ''
-
-        with open(app_var['path_oauth_setting'], 'w') as f:
-            f.write(json.dumps(old_oauth_data, sort_keys = True, indent = 4))
-
-    # End
+    conn.commit()
 
 
 def pw_encode(data, data2 = '', type_d = ''):
 def pw_encode(data, data2 = '', type_d = ''):
     if type_d == '':
     if type_d == '':
@@ -377,6 +325,11 @@ def edit_button():
         ["{{{+number data}}}", load_lang('edit_button_big')],
         ["{{{+number data}}}", load_lang('edit_button_big')],
         ["== name ==", load_lang('edit_button_paragraph')]
         ["== name ==", load_lang('edit_button_paragraph')]
     ]
     ]
+    
+    curs.execute("select html, plus from html_filter where kind = 'edit_top'")
+    db_data = curs.fetchall()
+    for get_data in db_data:
+        insert_list += [[get_data[1], get_data[0]]]
 
 
     data = ''
     data = ''
     for insert_data in insert_list:
     for insert_data in insert_list:
@@ -447,7 +400,7 @@ def other2(data):
         <script src="https://cdn.jsdelivr.net/npm/katex@0.10.1/dist/katex.min.js"
         <script src="https://cdn.jsdelivr.net/npm/katex@0.10.1/dist/katex.min.js"
                 integrity="sha384-2BKqo+exmr9su6dir+qCw08N2ZKRucY4PrGQPPWU1A7FtlCGjmEGFqXCv5nyM5Ij"
                 integrity="sha384-2BKqo+exmr9su6dir+qCw08N2ZKRucY4PrGQPPWU1A7FtlCGjmEGFqXCv5nyM5Ij"
                 crossorigin="anonymous"></script>
                 crossorigin="anonymous"></script>
-        <script src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/highlight.min.js"></script>
+        <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/highlight.min.js"></script>
     ''' + req_list]
     ''' + req_list]
 
 
     return data
     return data
@@ -753,7 +706,7 @@ def acl_check(name, tool = ''):
             if admin_check(5) == 1:
             if admin_check(5) == 1:
                 return 0
                 return 0
 
 
-            curs.execute("select dec from acl where title = ?", ['user:' + acl_n[0]])
+            curs.execute("select decu from acl where title = ?", ['user:' + acl_n[0]])
             acl_data = curs.fetchall()
             acl_data = curs.fetchall()
             if acl_data:
             if acl_data:
                 if acl_data[0][0] == 'all':
                 if acl_data[0][0] == 'all':
@@ -773,7 +726,7 @@ def acl_check(name, tool = ''):
         if re.search("^file:", name) and admin_check(None, 'file edit (' + name + ')') != 1:
         if re.search("^file:", name) and admin_check(None, 'file edit (' + name + ')') != 1:
             return 1
             return 1
 
 
-        curs.execute("select dec from acl where title = ?", [name])
+        curs.execute("select decu from acl where title = ?", [name])
         acl_data = curs.fetchall()
         acl_data = curs.fetchall()
         if acl_data:
         if acl_data:
             if acl_data[0][0] == 'user':
             if acl_data[0][0] == 'user':
@@ -994,6 +947,8 @@ def rd_plus(title, sub, date):
     else:
     else:
         curs.execute("insert into rd (title, sub, date) values (?, ?, ?)", [title, sub, date])
         curs.execute("insert into rd (title, sub, date) values (?, ?, ?)", [title, sub, date])
 
 
+    conn.commit()
+
 def history_plus(title, data, date, ip, send, leng, t_check = ''):
 def history_plus(title, data, date, ip, send, leng, t_check = ''):
     curs.execute("select id from history where title = ? order by id + 0 desc limit 1", [title])
     curs.execute("select id from history where title = ? order by id + 0 desc limit 1", [title])
     id_data = curs.fetchall()
     id_data = curs.fetchall()
@@ -1027,16 +982,14 @@ def leng_check(first, second):
     return all_plus
     return all_plus
 
 
 def number_check(data):
 def number_check(data):
-    if not data:
+    try:
+        int(data)
+        return data
+    except:
         return '1'
         return '1'
-    else:
-        if re.search('[^0-9]', data):
-            return '1'
-        else:
-            return data
 
 
 def edit_filter_do(data):
 def edit_filter_do(data):
-    if admin_check(1, 'edit_filter pass') != 1:
+    if admin_check(1) != 1:
         curs.execute("select regex, sub from filter")
         curs.execute("select regex, sub from filter")
         for data_list in curs.fetchall():
         for data_list in curs.fetchall():
             match = re.compile(data_list[0], re.I)
             match = re.compile(data_list[0], re.I)

+ 4 - 4
route/tool/init.py

@@ -29,10 +29,10 @@ server_set_var = {
         'display' : 'Markup',
         'display' : 'Markup',
         'require' : 'select',
         'require' : 'select',
         'default' : 'namumark',
         'default' : 'namumark',
-        'list' : ['namumark']
+        'list' : ['namumark', 'markdown']
     },
     },
     'encode' : {
     'encode' : {
-        'display' : 'Encrypt Method',
+        'display' : 'Encryption method',
         'require' : 'select',
         'require' : 'select',
         'default' : 'sha3',
         'default' : 'sha3',
         'list' : ['sha3', 'sha256']
         'list' : ['sha3', 'sha256']
@@ -45,11 +45,11 @@ def init(key):
     else:
     else:
         while 1:
         while 1:
             if server_set_var[key]['require'] == 'select':
             if server_set_var[key]['require'] == 'select':
-                list_ = '[' + ', '.join(server_set_var[key]['list']) + '] '
+                list_ = '[' + ', '.join(server_set_var[key]['list']) + ']'
             else:
             else:
                 list_ = ''
                 list_ = ''
 
 
-            print('{} ({}) {}:'.format(
+            print('{} ({}) {} : '.format(
                 server_set_var[key]['display'],
                 server_set_var[key]['display'],
                 server_set_var[key]['default'],
                 server_set_var[key]['default'],
                 list_
                 list_

+ 3 - 0
route/tool/mark.py

@@ -1,4 +1,5 @@
 from .set_mark.namu import namu
 from .set_mark.namu import namu
+from .set_mark.markdown import markdown
 
 
 import re
 import re
 import html
 import html
@@ -44,6 +45,8 @@ def namumark(title = '', data = None, num = 0):
     rep_data = curs.fetchall()
     rep_data = curs.fetchall()
     if rep_data[0][0] == 'namumark':
     if rep_data[0][0] == 'namumark':
         data = namu(conn, data, title, num)
         data = namu(conn, data, title, num)
+    elif rep_data[0][0] == 'markdown':
+        data = markdown(conn, data, title, num)
     else:
     else:
         data = ['', '', []]
         data = ['', '', []]
 
 

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

@@ -0,0 +1,14 @@
+from . import tool
+
+import datetime
+import html
+import re
+
+def markdown(conn, data, title, main_num):
+    curs = conn.cursor()
+    
+    data = '<div id="render_contect">' + re.sub('\r\n', '<br>', html.escape(data)) + '</div>'
+    plus_data = '<script>render_markdown();</script>'
+    backlink = []
+    
+    return [data, plus_data, backlink]

+ 16 - 28
route/tool/set_mark/namu.py

@@ -259,7 +259,7 @@ def middle_parser(data, fol_num, syntax_num, folding_num):
                                                         if folding_num == 0:
                                                         if folding_num == 0:
                                                             folding_num = 1
                                                             folding_num = 1
                                                         
                                                         
-                                                        data = re.sub('{{{#!folding ?((?:(?!\n).)*)\n?', '<div>' + str(folding_data[0]) + ' <div style="display: inline-block;"><a href="javascript:void(0);" onclick="folding(' + str(fol_num) + ');">[do]</a></div_end><div id="folding_' + str(fol_num) + '" style="display: none;"><div id="wiki_div" style="">', data, 1)
+                                                        data = re.sub('{{{#!folding ?((?:(?!\n).)*)\n?', '<div>' + str(folding_data[0]) + ' <div style="display: inline-block;"><a href="javascript:void(0);" onclick="folding(' + str(fol_num) + ');">[+]</a></div_end><div id="folding_' + str(fol_num) + '" style="display: none;"><div id="wiki_div" style="">', data, 1)
                                                         
                                                         
                                                         fol_num += 1
                                                         fol_num += 1
                                                     else:
                                                     else:
@@ -349,24 +349,6 @@ def middle_parser(data, fol_num, syntax_num, folding_num):
             break
             break
 
 
     return [data, [fol_num, syntax_num, folding_num]]
     return [data, [fol_num, syntax_num, folding_num]]
-    
-def link_fix(main_link):
-    if re.search('^:', main_link):
-        main_link = re.sub('^:', '', main_link)
-
-    main_link = re.sub('^사용자:', 'user:', main_link)
-    main_link = re.sub('^파일:', 'file:', main_link)
-    main_link = re.sub('^분류:', 'category:', main_link)
-
-    other_link = re.search('(#.+)$', main_link)
-    if other_link:
-        other_link = other_link.groups()[0]
-
-        main_link = re.sub('(#.+)$', '', main_link)
-    else:
-        other_link = ''
-        
-    return [main_link, other_link]
 
 
 def namu(conn, data, title, main_num):
 def namu(conn, data, title, main_num):
     curs = conn.cursor()
     curs = conn.cursor()
@@ -525,13 +507,13 @@ def namu(conn, data, title, main_num):
     if redirect:
     if redirect:
         redirect = redirect.groups()[0]
         redirect = redirect.groups()[0]
         
         
-        return_link = link_fix(redirect)
+        return_link = tool.link_fix(redirect)
         main_link = return_link[0]
         main_link = return_link[0]
         other_link = return_link[1]
         other_link = return_link[1]
         
         
-        backlink += [[title, main_link, 'redirect']]
+        backlink += [[title, main_link + other_link, 'redirect']]
         
         
-        data = redirect_re.sub('\n * ' + title + ' - [[' + main_link + ']]\n', data, 1)
+        data = redirect_re.sub('\n * ' + title + ' - [[' + main_link + other_link + ']]\n', data, 1)
 
 
     no_toc_re = re.compile('\[(?:목차|toc)\((?:no)\)\]\n', re.I)
     no_toc_re = re.compile('\[(?:목차|toc)\((?:no)\)\]\n', re.I)
     toc_re = re.compile('\[(?:목차|toc)\]', re.I)
     toc_re = re.compile('\[(?:목차|toc)\]', re.I)
@@ -745,7 +727,7 @@ def namu(conn, data, title, main_num):
 
 
     data = table_start(data)
     data = table_start(data)
 
 
-    category = '\n<div id="cate_all"><hr><div id="cate">Category : '
+    category = '<div id="cate_all"><hr><div id="cate">Category : '
     category_re = re.compile('^(?:category|분류):', re.I)
     category_re = re.compile('^(?:category|분류):', re.I)
     while 1:
     while 1:
         link = re.search('\[\[((?:(?!\[\[|\]\]).)+)\]\]', data)
         link = re.search('\[\[((?:(?!\[\[|\]\]).)+)\]\]', data)
@@ -860,7 +842,7 @@ def namu(conn, data, title, main_num):
             elif re.search('^http(s)?:\/\/', main_link):
             elif re.search('^http(s)?:\/\/', main_link):
                 data = re.sub('\[\[((?:(?!\[\[|\]\]).)+)\]\]', '<a id="out_link" rel="nofollow" href="' + main_link + '">' + see_link + '</a>', data, 1)
                 data = re.sub('\[\[((?:(?!\[\[|\]\]).)+)\]\]', '<a id="out_link" rel="nofollow" href="' + main_link + '">' + see_link + '</a>', data, 1)
             else:
             else:
-                return_link = link_fix(main_link)
+                return_link = tool.link_fix(main_link)
                 main_link = return_link[0]
                 main_link = return_link[0]
                 other_link = return_link[1]
                 other_link = return_link[1]
 
 
@@ -906,7 +888,7 @@ def namu(conn, data, title, main_num):
     footnote_dict = {}
     footnote_dict = {}
     footnote_re = {}
     footnote_re = {}
     
     
-    footdata_all = '\n<hr><ul id="footnote_data">'
+    footdata_all = '<hr><ul id="footnote_data">'
     
     
     re_footnote = re.compile('(?:\[\*((?:(?! |\]).)*)(?: ((?:(?!(?:\[\*|\])).)+))?\]|(\[(?:각주|footnote)\]))')
     re_footnote = re.compile('(?:\[\*((?:(?! |\]).)*)(?: ((?:(?!(?:\[\*|\])).)+))?\]|(\[(?:각주|footnote)\]))')
     while 1:
     while 1:
@@ -927,7 +909,7 @@ def namu(conn, data, title, main_num):
                 data = re_footnote.sub(footdata_all + '</ul>', data, 1)
                 data = re_footnote.sub(footdata_all + '</ul>', data, 1)
                 
                 
                 footnote_all = []
                 footnote_all = []
-                footdata_all = '\n<hr><ul id="footnote_data">'
+                footdata_all = '<hr><ul id="footnote_data">'
             else:
             else:
                 footnote = footnote_data[1]
                 footnote = footnote_data[1]
                 footnote_name = footnote_data[0]
                 footnote_name = footnote_data[0]
@@ -975,14 +957,15 @@ def namu(conn, data, title, main_num):
         footdata_all += '<li><a href="#rfn-' + str(footdata[0]) + '">(' + footdata[1] + ')</a> <span id="fn-' + str(footdata[0]) + '">' + footdata_in + '</span></li>'
         footdata_all += '<li><a href="#rfn-' + str(footdata[0]) + '">(' + footdata[1] + ')</a> <span id="fn-' + str(footdata[0]) + '">' + footdata_in + '</span></li>'
 
 
     footdata_all += '</ul>'
     footdata_all += '</ul>'
-    if footdata_all == '\n<hr><ul id="footnote_data"></ul>':
+    if footdata_all == '<hr><ul id="footnote_data"></ul>':
         footdata_all = ''
         footdata_all = ''
 
 
     data = re.sub('\n$', footdata_all, data + '\n', 1)
     data = re.sub('\n$', footdata_all, data + '\n', 1)
 
 
     category += '</div></div>'
     category += '</div></div>'
+    category = re.sub(' \| <\/div><\/div>$', '</div></div>', category)
 
 
-    if category == '\n<div id="cate_all"><hr><div id="cate">Category : </div></div>':
+    if category == '<div id="cate_all"><hr><div id="cate">Category : </div></div>':
         category = ''
         category = ''
 
 
     data += category
     data += category
@@ -1034,6 +1017,7 @@ def namu(conn, data, title, main_num):
     data = re.sub('<\/td_end>', '</td>', data)
     data = re.sub('<\/td_end>', '</td>', data)
     data = re.sub('<include>(?P<in><a (?:[^>]+)>)\n', '\g<in>', data)
     data = re.sub('<include>(?P<in><a (?:[^>]+)>)\n', '\g<in>', data)
     data = re.sub('\n<\/include>', '', data)
     data = re.sub('\n<\/include>', '', data)
+    data = re.sub('<\/ul>\n', '</ul>', data)
     
     
     data = re.sub('(?P<in><\/h[0-9]>)(\n)+', '\g<in>', data)
     data = re.sub('(?P<in><\/h[0-9]>)(\n)+', '\g<in>', data)
     data = re.sub('\n\n<ul>', '\n<ul>', data)
     data = re.sub('\n\n<ul>', '\n<ul>', data)
@@ -1042,7 +1026,11 @@ def namu(conn, data, title, main_num):
     data = re.sub('(\n)+<hr><ul id="footnote_data">', '<hr><ul id="footnote_data">', data)
     data = re.sub('(\n)+<hr><ul id="footnote_data">', '<hr><ul id="footnote_data">', data)
     data = re.sub('(?P<in><td(((?!>).)*)>)\n', '\g<in>', data)
     data = re.sub('(?P<in><td(((?!>).)*)>)\n', '\g<in>', data)
     data = re.sub('(\n)?<hr>(\n)?', '<hr>', data)
     data = re.sub('(\n)?<hr>(\n)?', '<hr>', data)
+
     data = re.sub('<\/ul>\n\n<ul>', '</ul>\n<ul>', data)
     data = re.sub('<\/ul>\n\n<ul>', '</ul>\n<ul>', data)
+    data = re.sub('<\/ul>\n<ul>', '</ul><ul>', data)
+    data = re.sub('\n<\/ul>', '</ul>', data)
+
     data = re.sub('\n', '<br>', data)
     data = re.sub('\n', '<br>', data)
 
 
     return [data, plus_data, backlink]
     return [data, plus_data, backlink]

+ 18 - 0
route/tool/set_mark/tool.py

@@ -29,6 +29,24 @@ def ip_check(d_type = 0):
             ip = '-'
             ip = '-'
             
             
     return str(ip)
     return str(ip)
+    
+def link_fix(main_link):
+    if re.search('^:', main_link):
+        main_link = re.sub('^:', '', main_link)
+
+    main_link = re.sub('^사용자:', 'user:', main_link)
+    main_link = re.sub('^파일:', 'file:', main_link)
+    main_link = re.sub('^분류:', 'category:', main_link)
+
+    other_link = re.search('(#.+)$', main_link)
+    if other_link:
+        other_link = other_link.groups()[0]
+
+        main_link = re.sub('(#.+)$', '', main_link)
+    else:
+        other_link = ''
+        
+    return [main_link, other_link]
 
 
 def savemark(data):
 def savemark(data):
     data = re.sub("\[date\(now\)\]", get_time(), data)
     data = re.sub("\[date\(now\)\]", get_time(), data)

+ 23 - 116
route/topic.py

@@ -76,128 +76,35 @@ def topic_2(conn, name, sub):
         
         
         return redirect('/topic/' + url_pas(name) + '/sub/' + url_pas(sub) + '#reload')
         return redirect('/topic/' + url_pas(name) + '/sub/' + url_pas(sub) + '#reload')
     else:
     else:
-        curs.execute("select title from rd where title = ? and sub = ? and stop = 'O'", [name, sub])
-        close_data = curs.fetchall()
-        
-        curs.execute("select title from rd where title = ? and sub = ? and stop = 'S'", [name, sub])
-        stop_data = curs.fetchall()
-        
-        display = ''
-        all_data = ''
         data = ''
         data = ''
-        number = 1
+    
+        curs.execute("select stop from rd where title = ? and sub = ? and stop != ''", [name, sub])
+        close_data = curs.fetchall()
         
         
-        if (close_data or stop_data) and admin != 1:
+        if close_data and admin != 1:
             display = 'display: none;'
             display = 'display: none;'
-        
-        curs.execute("select data, id, date, ip, block, top from topic where title = ? and sub = ? order by id + 0 asc", [name, sub])
-        topic = curs.fetchall()
-        
-        curs.execute("select data, id, date, ip from topic where title = ? and sub = ? and top = 'O' order by id + 0 asc", [name, sub])
-        for topic_data in curs.fetchall():                   
-            who_plus = ''
-            
-            curs.execute("select who from re_admin where what = ? order by time desc limit 1", ['notice (' + name + ' - ' + sub + '#' + topic_data[1] + ')'])
-            topic_data_top = curs.fetchall()
-            if topic_data_top:
-                who_plus += ' <span style="margin-right: 5px;">@' + topic_data_top[0][0] + ' </span>'
-                                
-            all_data += '''
-                <table id="toron">
-                    <tbody>
-                        <tr>
-                            <td id="toron_color_red">
-                                <a href="#''' + topic_data[1] + '''">
-                                    #''' + topic_data[1] + '''
-                                </a> ''' + ip_pas(topic_data[3]) + who_plus + ''' <span style="float: right;">''' + topic_data[2] + '''</span>
-                            </td>
-                        </tr>
-                        <tr>
-                            <td>''' + render_set(data = topic_data[0]) + '''</td>
-                        </tr>
-                    </tbody>
-                </table>
-                <hr class=\"main_hr\">
-            '''    
-
-        for topic_data in topic:
-            user_write = topic_data[0]
-
-            if number == 1:
-                start = topic_data[3]
-
-            if topic_data[4] == 'O':
-                blind_data = 'id="toron_color_grey"'
-                
-                if admin != 1:
-                    curs.execute("select who from re_admin where what = ? order by time desc limit 1", ['blind (' + name + ' - ' + sub + '#' + str(number) + ')'])
-                    who_blind = curs.fetchall()
-                    if who_blind:
-                        user_write = '[[user:' + who_blind[0][0] + ']] ' + load_lang('hide')
-                    else:
-                        user_write = load_lang('hide')
-            else:
-                blind_data = ''
-
-            user_write = render_set(data = user_write)
-            ip = ip_pas(topic_data[3])
-            
-            curs.execute('select acl from user where id = ?', [topic_data[3]])
-            user_acl = curs.fetchall()
-            if user_acl and user_acl[0][0] != 'user':
-                ip += ' <a href="javascript:void(0);" title="' + load_lang('admin') + '">★</a>'
-
-            if admin == 1 or blind_data == '':
-                ip += ' <a href="/topic/' + url_pas(name) + '/sub/' + url_pas(sub) + '/admin/' + str(number) + '">(' + load_lang('discussion_tool') + ')</a>'
-
-            curs.execute("select end from ban where block = ?", [topic_data[3]])
-            if curs.fetchall():
-                ip += ' <a href="javascript:void(0);" title="' + load_lang('blocked') + '">†</a>'
-                    
-            if topic_data[5] == '1':
-                color = '_blue'
-            elif topic_data[3] == start:
-                color = '_green'
-            else:
-                color = ''
-                
-            if user_write == '':
-                user_write = '<br>'
-                         
-            all_data += '''
-                <table id="toron">
-                    <tbody>
-                        <tr>
-                            <td id="toron_color''' + color + '''">
-                                <a href="javascript:void(0);" id="''' + str(number) + '">#' + str(number) + '</a> ' + ip + '''</span>
-                            </td>
-                        </tr>
-                        <tr ''' + blind_data + '''>
-                            <td>''' + user_write + '''</td>
-                        </tr>
-                    </tbody>
-                </table>
-                <hr class=\"main_hr\">
-            '''
-
-            number += 1
-
-        if ban != 1 or admin == 1:
-            data += '''
-                <div id="plus"></div>
-                <script>topic_load("''' + name + '''", "''' + sub + '''", "''' + str(number) + '''");</script>
-                <a id="reload" href="javascript:void(0);" onclick="reload();">(''' + load_lang('reload') + ''')</a> <a href="/topic/''' + url_pas(name) + '''/sub/''' + url_pas(sub) + '''/tool">(''' + load_lang('topic_tool') + ''')</a>
+        else:
+            display = ''
+
+        data += '''
+            <div id="top_topic"></div>
+            <div id="main_topic"></div>
+            <div id="plus_topic"></div>
+            <script>topic_top_load("''' + name + '''", "''' + sub + '''");</script>
+            <a id="reload" href="javascript:void(0);" onclick="topic_reload();">(''' + load_lang('reload') + ''')</a> <a href="/topic/''' + url_pas(name) + '''/sub/''' + url_pas(sub) + '''/tool">(''' + load_lang('topic_tool') + ''')</a>
+            <hr class=\"main_hr\">
+            <form style="''' + display + '''" method="post">
+                <textarea style="height: 100px;" name="content"></textarea>
                 <hr class=\"main_hr\">
                 <hr class=\"main_hr\">
-                <form style="''' + display + '''" method="post">
-                    <textarea style="height: 100px;" name="content"></textarea>
-                    <hr class=\"main_hr\">
-                    ''' + captcha_get() + (ip_warring() if display == '' else '') + '''
-                    <button type="submit">''' + load_lang('send') + '''</button>
-                </form>
-            '''
+                ''' + captcha_get() + (ip_warring() if display == '' else '') + '''
+                <button type="submit">''' + load_lang('send') + '''</button>
+            </form>
+        '''
 
 
         return easy_minify(flask.render_template(skin_check(), 
         return easy_minify(flask.render_template(skin_check(), 
             imp = [name, wiki_set(), custom(), other2([' (' + load_lang('discussion') + ')', 0])],
             imp = [name, wiki_set(), custom(), other2([' (' + load_lang('discussion') + ')', 0])],
-            data = '<h2 id="topic_top_title">' + sub + '</h2>' + all_data + data,
+            data = '''
+                <h2 id="topic_top_title">''' + sub + '''</h2>
+                ''' + data,
             menu = [['topic/' + url_pas(name), load_lang('list')]]
             menu = [['topic/' + url_pas(name), load_lang('list')]]
         ))
         ))

+ 31 - 49
route/topic_admin.py

@@ -8,67 +8,49 @@ def topic_admin_2(conn, name, sub, num):
     if not data:
     if not data:
         return redirect('/topic/' + url_pas(name) + '/sub/' + url_pas(sub))
         return redirect('/topic/' + url_pas(name) + '/sub/' + url_pas(sub))
 
 
-    ban = ''
+    ban = '''
+        <h2>''' + load_lang('state') + '''</h2>
+        <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>
+            <li>
+                <a href="/topic/''' + url_pas(name) + '/sub/' + url_pas(sub) + '/raw/' + str(num) + '''">''' + load_lang('raw') + '''</a>
+            </li>
+        </ul>
+    '''
 
 
     if admin_check(3) == 1:
     if admin_check(3) == 1:
-        ban +=  '''
-            </ul>
-            <br>
-            <h2>''' + load_lang('admin_tool') + '''</h2>
-            <ul>
-        '''
-        is_ban = '<li><a href="/topic/' + url_pas(name) + '/sub/' + url_pas(sub) + '/b/' + str(num) + '">'
-
-        if data[0][0] == 'O':
-            is_ban += load_lang('hide_release')
-        else:
-            is_ban += load_lang('hide')
-        
-        is_ban +=   '''
-                        </a>
-                    </li>
-                    <li>
-                        <a href="/topic/''' + url_pas(name) + '/sub/' + url_pas(sub) + '/notice/' + str(num) + '''">
-                    '''
-
         curs.execute("select id from topic where title = ? and sub = ? and id = ? and top = 'O'", [name, sub, str(num)])
         curs.execute("select id from topic where title = ? and sub = ? and id = ? and top = 'O'", [name, sub, str(num)])
-        if curs.fetchall():
-            is_ban += load_lang('notice_release')
-        else:
-            is_ban += load_lang('notice') + ''
-        
-        is_ban += '</a></li></ul>'
-        ban += '<li><a href="/ban/' + url_pas(data[0][1]) + '">'
+        top_topic_d = curs.fetchall()
 
 
         curs.execute("select end from ban where block = ?", [data[0][1]])
         curs.execute("select end from ban where block = ?", [data[0][1]])
-        if curs.fetchall():
-            ban += load_lang('ban_release')
-        else:
-            ban += load_lang('ban')
+        user_ban_d = curs.fetchall()
         
         
-        ban += '</a></li>' + is_ban
-
-    ban +=  '''
-            </ul>
+        ban += '''
             <br>
             <br>
-            <h2>''' + load_lang('other_tool') + '''</h2>
+            <h2>''' + load_lang('admin_tool') + '''</h2>
             <ul>
             <ul>
                 <li>
                 <li>
-                    <a href="/topic/''' + url_pas(name) + '/sub/' + url_pas(sub) + '/raw/' + str(num) + '''">''' + load_lang('raw') + '''</a>
+                    <a href="/ban/''' + url_pas(data[0][1]) + '''">
+                        ''' + (load_lang('ban_release') if user_ban_d else load_lang('ban')) + '''
+                    </a>
                 </li>
                 </li>
-            '''
-    ban = '<li>' + load_lang('time') + ' : ' + data[0][2] + '</li>' + ban
-    
-    if ip_or_user(data[0][1]) == 1:
-        ban = '<li>' + load_lang('writer') + ' : ' + data[0][1] + ' <a href="/record/' + url_pas(data[0][1]) + '">(' + load_lang('record') + ')</a></li>' + ban
-    else:
-        ban =   '''
                 <li>
                 <li>
-                    ''' + load_lang('writer') + ' : <a href="/w/user:' + data[0][1] + '">' + data[0][1] + '</a> <a href="/record/' + url_pas(data[0][1]) + '">(' + load_lang('record') + ''')</a>
+                    <a href="/topic/' + url_pas(name) + '/sub/' + url_pas(sub) + '/b/' + str(num) + '">
+                    ''' + (load_lang('hide_release') if data[0][0] == 'O' else load_lang('hide')) + '''
+                    </a>
                 </li>
                 </li>
-                ''' + ban
-
-    ban = '<h2>' + load_lang('state') + '</h2><ul>' + ban
+                <li>
+                    <a href="/topic/''' + url_pas(name) + '/sub/' + url_pas(sub) + '/notice/' + str(num) + '''">
+                        ''' + (load_lang('pinned_release') if top_topic_d else load_lang('pinned')) + '''
+                    </a>
+                </li>
+            </ul>
+        '''
 
 
     return easy_minify(flask.render_template(skin_check(), 
     return easy_minify(flask.render_template(skin_check(), 
         imp = [load_lang('discussion_tool'), wiki_set(), custom(), other2([' (#' + str(num) + ')', 0])],
         imp = [load_lang('discussion_tool'), wiki_set(), custom(), other2([' (#' + str(num) + ')', 0])],

+ 26 - 10
route/topic_close_list.py

@@ -26,11 +26,11 @@ def topic_close_list_2(conn, name, tool):
         if tool == 'close':
         if tool == 'close':
             curs.execute("select sub from rd where title = ? and stop = 'O' order by sub asc", [name])
             curs.execute("select sub from rd where title = ? and stop = 'O' order by sub asc", [name])
             
             
-            sub = load_lang('close') + ''
+            sub = load_lang('closed_discussion')
         elif tool == 'agree':
         elif tool == 'agree':
             curs.execute("select sub from rd where title = ? and agree = 'O' order by sub asc", [name])
             curs.execute("select sub from rd where title = ? and agree = 'O' order by sub asc", [name])
             
             
-            sub = load_lang('agreement') + ''
+            sub = load_lang('agreed_discussion')
         else:
         else:
             curs.execute("select sub from rd where title = ? order by date desc", [name])
             curs.execute("select sub from rd where title = ? order by date desc", [name])
             
             
@@ -39,14 +39,17 @@ def topic_close_list_2(conn, name, tool):
             menu = [['w/' + url_pas(name), load_lang('document')]]
             menu = [['w/' + url_pas(name), load_lang('document')]]
             
             
             plus =  '''
             plus =  '''
-                    <a href="/topic/''' + url_pas(name) + '''/close">(''' + load_lang('close') + ''')</a> <a href="/topic/''' + url_pas(name) + '''/agree">(''' + load_lang('agreement') + ''')</a>
-                    <hr class=\"main_hr\">
-                    <input placeholder="''' + load_lang('discussion_name') + '''" name="topic" type="text">
-                    <hr class=\"main_hr\">
-                    <button type="submit">''' + load_lang('go') + '''</button>
-                    '''
+                <a href="/topic/''' + url_pas(name) + '''/close">(''' + load_lang('closed_discussion') + ''')</a> <a href="/topic/''' + url_pas(name) + '''/agree">(''' + load_lang('agreed_discussion') + ''')</a>
+                <hr class=\"main_hr\">
+                <input placeholder="''' + load_lang('discussion_name') + '''" name="topic" type="text">
+                <hr class=\"main_hr\">
+                <button type="submit">''' + load_lang('go') + '''</button>
+            '''
 
 
+        t_num = 0
         for data in curs.fetchall():
         for data in curs.fetchall():
+            t_num += 1
+            
             curs.execute("select data, date, ip, block from topic where title = ? and sub = ? and id = '1'", [name, data[0]])
             curs.execute("select data, date, ip, block from topic where title = ? and sub = ? and id = '1'", [name, data[0]])
             if curs.fetchall():                
             if curs.fetchall():                
                 it_p = 0
                 it_p = 0
@@ -57,13 +60,26 @@ def topic_close_list_2(conn, name, tool):
                         it_p = 1
                         it_p = 1
                 
                 
                 if it_p != 1:
                 if it_p != 1:
-                    div += '<h2><a href="/topic/' + url_pas(name) + '/sub/' + url_pas(data[0]) + '">' + data[0] + '</a></h2>'
+                    curs.execute("select id from topic where title = ? and sub = ? order by date desc limit 1", [name, data[0]])
+                    t_data = curs.fetchall()
+                
+                    div += '''
+                        <h2><a href="/topic/''' + url_pas(name) + '''/sub/''' + url_pas(data[0]) + '''">''' + str(t_num) + '''. ''' + data[0] + '''</a></h2>
+                        <div id="topic_pre_''' + str(t_num) + '''"></div>
+                        <div id="topic_back_pre_''' + str(t_num) + '''"></div>
+                        <script>
+                            topic_list_load("''' + name + '''", "''' + data[0] + '''", "1", "topic_pre_''' + str(t_num) + '''");
+                            if("''' + str(t_num) + '''" !== "1") {
+                                topic_list_load("''' + name + '''", "''' + data[0] + '''", "''' + t_data[0][0] + '''", "topic_back_pre_''' + str(t_num) + '''");
+                            }
+                        </script>
+                    '''
 
 
         if div == '':
         if div == '':
             plus = re.sub('^<br>', '', plus)
             plus = re.sub('^<br>', '', plus)
         
         
         return easy_minify(flask.render_template(skin_check(), 
         return easy_minify(flask.render_template(skin_check(), 
             imp = [name, wiki_set(), custom(), other2([' (' + sub + ')', 0])],
             imp = [name, wiki_set(), custom(), other2([' (' + sub + ')', 0])],
-            data =  '<form method="post">' + div + plus + '</form>',
+            data = '<form method="post">' + div + plus + '</form>',
             menu = menu
             menu = menu
         ))
         ))

+ 67 - 36
route/topic_stop.py

@@ -1,64 +1,95 @@
 from .tool.func import *
 from .tool.func import *
 
 
-def topic_stop_2(conn, name, sub, tool):
+def topic_stop_2(conn, name, sub):
     curs = conn.cursor()
     curs = conn.cursor()
 
 
-    if admin_check(3, 'topic ' + tool + ' (' + name + ' - ' + sub + ')') != 1:
+    if admin_check(3) != 1:
         return re_error('/error/3')
         return re_error('/error/3')
 
 
     ip = ip_check()
     ip = ip_check()
     time = get_time()
     time = get_time()
 
 
-    if flask.request.method == 'POST' or tool == 'agree' or tool == 'stop':
+    if flask.request.method == 'POST':
         curs.execute("select id from topic where title = ? and sub = ? order by id + 0 desc limit 1", [name, sub])
         curs.execute("select id from topic where title = ? and sub = ? order by id + 0 desc limit 1", [name, sub])
         topic_check = curs.fetchall()
         topic_check = curs.fetchall()
         if topic_check:
         if topic_check:
-            if tool == 'agree':
-                curs.execute("select title from rd where title = ? and sub = ? and agree = 'O'", [name, sub])
-                if curs.fetchall():
-                    curs.execute("insert into topic (id, title, sub, data, date, ip, block, top) values (?, ?, ?, 'ok', ?, ?, '', '1')", [str(int(topic_check[0][0]) + 1), name, sub, time, ip])
-                    curs.execute("update rd set agree = '' where title = ? and sub = ?", [name, sub])
-                else:
-                    curs.execute("insert into topic (id, title, sub, data, date, ip, block, top) values (?, ?, ?, 'break', ?, ?, '', '1')", [str(int(topic_check[0][0]) + 1), name, sub, time, ip])
-                    curs.execute("update rd set agree = 'O' where title = ? and sub = ?", [name, sub])
+            stop_d = flask.request.form.get('stop_d', '')
+            why_d = flask.request.form.get('why', '')
+            agree_d = flask.request.form.get('agree', '')
+
+            curs.execute("update rd set stop = ?, agree = ? where title = ? and sub = ?", [
+                stop_d,
+                agree_d,
+                name, 
+                sub
+            ])
+
+            if stop_d == 'S':
+                t_state = 'Stop'
+            elif stop_d == 'O':
+                t_state = 'Close'
             else:
             else:
-                if tool == 'close':
-                    why = flask.request.form.get('why', '')
-                    set_list = [
-                        'O', 
-                        'S', 
-                        'close' + (('[br][br]why : ' + why) if why else ''), 
-                        'open' + (('[br][br]why : ' + why) if why else '')
-                    ]
-                elif tool == 'stop':
-                    set_list = ['', 'O', 'stop', 'restart']
-                else:
-                    return redirect('/topic/' + url_pas(name) + '/sub/' + url_pas(sub))
+                t_state = 'Normal'
+
+            curs.execute("insert into topic (id, title, sub, data, date, ip, block, top) values (?, ?, ?, ?, ?, ?, '', '1')", [
+                str(int(topic_check[0][0]) + 1), 
+                name, 
+                sub, 
+                t_state + (' (Agree)' if agree_d != '' else '') + (('[br][br]Why : ' + why_d) if why_d else ''), 
+                time, 
+                ip
+            ])
 
 
-                curs.execute("select title from rd where title = ? and sub = ? and stop = ?", [name, sub, set_list[0]])
-                if curs.fetchall():
-                    curs.execute("insert into topic (id, title, sub, data, date, ip, block, top) values (?, ?, ?, ?, ?, ?, '', '1')", [str(int(topic_check[0][0]) + 1), name, sub, set_list[3], time, ip])
-                    curs.execute("update rd set stop = '' where title = ? and sub = ?", [name, sub])
-                else:
-                    curs.execute("insert into topic (id, title, sub, data, date, ip, block, top) values (?, ?, ?, ?, ?, ?, '', '1')", [str(int(topic_check[0][0]) + 1), name, sub, set_list[2], time, ip])
-                    curs.execute("update rd set stop = ? where title = ? and sub = ?", [set_list[0], name, sub])
-            
             rd_plus(name, sub, time)
             rd_plus(name, sub, time)
-            
-            conn.commit()
 
 
         return redirect('/topic/' + url_pas(name) + '/sub/' + url_pas(sub))    
         return redirect('/topic/' + url_pas(name) + '/sub/' + url_pas(sub))    
     else:
     else:
+        stop_d_list = ''
+        agree_check = ''
+
+        curs.execute("select stop, agree from rd where title = ? and sub = ? limit 1", [name, sub])
+        rd_d = curs.fetchall()
+        if rd_d[0][0] == 'O':
+            stop_d_list += '''
+                <option value="O">Close</option>
+                <option value="">Normal</option>
+                <option value="S">Stop</option>
+            '''
+        elif rd_d[0][0] == 'S':
+            stop_d_list += '''
+                <option value="S">Stop</option>
+                <option value="">Normal</option>
+                <option value="O">Close</option>
+            '''
+        else:
+            stop_d_list += '''
+                <option value="">Normal</option>
+                <option value="S">Stop</option>
+                <option value="O">Close</option>
+            '''
+
+        if rd_d[0][1] == 'O':
+            agree_check = 'checked="checked"'
+        else:
+            agree_check = ''
+
         return easy_minify(flask.render_template(skin_check(),
         return easy_minify(flask.render_template(skin_check(),
-            imp = [name, wiki_set(), custom(), other2([' (' + tool + ')', 0])],
+            imp = [name, wiki_set(), custom(), other2([' (topic_tool)', 0])],
             data = '''
             data = '''
-                <span>''' + load_lang('markup_enabled') + '''</span>
                 <hr class=\"main_hr\">
                 <hr class=\"main_hr\">
                 <form method="post">
                 <form method="post">
+                    <select name="stop_d">
+                        ''' + stop_d_list + '''
+                    </select>
+                    <hr class=\"main_hr\">
+                    <input type="checkbox" name="agree" value="O" ''' + agree_check + '''> Agree
+                    <hr class=\"main_hr\">
                     <input placeholder="''' + load_lang('why') + '''" name="why" type="text">
                     <input placeholder="''' + load_lang('why') + '''" name="why" type="text">
                     <hr class=\"main_hr\">
                     <hr class=\"main_hr\">
+                    <span>''' + load_lang('markup_enabled') + '''</span>
+                    <hr class=\"main_hr\">
                     <button type="submit">''' + load_lang('save') + '''</button>
                     <button type="submit">''' + load_lang('save') + '''</button>
                 </form>
                 </form>
             ''',
             ''',
-            menu = [['topic/' + url_pas(name) + '/sub/' + url_pas(sub), load_lang('return')]]
+            menu = [['topic/' + url_pas(name) + '/sub/' + url_pas(sub) + '/tool', load_lang('return')]]
         ))
         ))

+ 27 - 32
route/topic_tool.py

@@ -2,45 +2,40 @@ from .tool.func import *
 
 
 def topic_tool_2(conn, name, sub):
 def topic_tool_2(conn, name, sub):
     curs = conn.cursor()
     curs = conn.cursor()
-    
-    curs.execute("select id from topic where title = ? and sub = ? limit 1", [name, sub])
-    topic_exist = curs.fetchall()
-    if not topic_exist:
-        return re_error('/topic/' + url_pas(name) + '/sub/' + url_pas(sub))
 
 
-    all_data = ''
+    data = ''
 
 
-    if admin_check(3) == 1:
-        all_data = '<h2>' + load_lang('topic_state') + '</h2><ul><li><a href="/topic/' + url_pas(name) + '/sub/' + url_pas(sub) + '/tool/close">'
-
-        curs.execute("select title from rd where title = ? and sub = ? and stop = 'O'", [name, sub])
-        if curs.fetchall():
-            all_data += load_lang('topic_open')
+    curs.execute("select stop, agree from rd where title = ? and sub = ?", [name, sub])
+    close_data = curs.fetchall()
+    if close_data:
+        if close_data[0][0] == 'S':
+            t_state = 'Stop'
+        elif close_data[0][0] == 'O':
+            t_state = 'Close'
         else:
         else:
-            all_data += load_lang('topic_close')
-        
-        all_data += '</a></li><li><a href="/topic/' + url_pas(name) + '/sub/' + url_pas(sub) + '/tool/stop">'
+            t_state = 'Normal'
+    else:
+        t_state = 'Normal'
 
 
-        curs.execute("select title from rd where title = ? and sub = ? and stop = 'S'", [name, sub])
-        if curs.fetchall():
-            all_data += load_lang('topic_restart')
-        else:
-            all_data += load_lang('topic_stop')
-            
-        all_data += '</a></li><li><a href="/topic/' + url_pas(name) + '/sub/' + url_pas(sub) + '/tool/agree">'
-        
-        curs.execute("select title from rd where title = ? and sub = ? and agree = 'O'", [name, sub])
-        if curs.fetchall():
-            all_data += load_lang('topic_destruction')
-        else:
-            all_data += load_lang('topic_agreement')
-        
-        all_data += '</a></li></ul>'
+    if admin_check(3) == 1:
+        data = '''
+            <h2>''' + load_lang('admin_tool') + '''</h2>
+            <ul>
+                <li><a href="/topic/''' + url_pas(name) + '/sub/' + url_pas(sub) + '''/setting"> Topic setting</a></li>
+            </ul>
+        '''
 
 
-    all_data += '<h2>' + load_lang('tool') + '</h2><ul><li><a id="reload" href="javascript:void(0);" onclick="req_alarm();">' + load_lang('use_push_alarm') + '</a></li></ul>'
+    print(close_data)
+    data += '''
+        <h2>''' + load_lang('tool') + '''</h2>
+        <ul>
+            <li><a id="reload" href="javascript:void(0);" onclick="req_alarm();">''' + load_lang('use_push_alarm') + '''</a></li>
+            <li>''' + load_lang('topic_state') + ''' : ''' + t_state + '' + (' (Agree)' if close_data and (close_data[0][1] == 'O') else '') + '''</li>
+        </ul>
+    '''
 
 
     return easy_minify(flask.render_template(skin_check(), 
     return easy_minify(flask.render_template(skin_check(), 
         imp = [name, wiki_set(), custom(), other2([' (' + load_lang('topic_tool') + ')', 0])],
         imp = [name, wiki_set(), custom(), other2([' (' + load_lang('topic_tool') + ')', 0])],
-        data = all_data,
+        data = data,
         menu = [['topic/' + url_pas(name) + '/sub/' + url_pas(sub), load_lang('return')]]
         menu = [['topic/' + url_pas(name) + '/sub/' + url_pas(sub), load_lang('return')]]
     ))
     ))

+ 4 - 43
route/user_info.py

@@ -4,39 +4,6 @@ def user_info_2(conn):
     curs = conn.cursor()
     curs = conn.cursor()
 
 
     ip = ip_check()
     ip = ip_check()
-    
-    curs.execute("select acl from user where id = ?", [ip])
-    data = curs.fetchall()
-    if ban_check() == 0:
-        if data:
-            if data[0][0] != 'user':
-                acl = data[0][0]
-            else:
-                acl = load_lang('member')
-        else:
-            acl = load_lang('normal')
-    else:
-        acl = load_lang('blocked')
-
-        match = re.search("^([0-9]{1,3}\.[0-9]{1,3})", ip)
-        if match:
-            match = match.groups()[0]
-        else:
-            match = '-'
-
-        curs.execute("select end, login, band from ban where block = ? or block = ?", [ip, match])
-        block_data = curs.fetchall()
-        if block_data:
-            if block_data[0][0] != '':
-                acl += ' (' + load_lang('period') + ' : ' + block_data[0][0] + ')'
-            else:
-                acl += ' (' + load_lang('limitless') + ')'        
-
-            if block_data[0][1] != '':
-                acl += ' (' + load_lang('login_able') + ')'
-
-            if block_data[0][2] == 'O':
-                acl += ' (' + load_lang('band_blocked') + ')'
 
 
     curs.execute('select name from alarm where name = ? limit 1', [ip_check()])
     curs.execute('select name from alarm where name = ? limit 1', [ip_check()])
     if curs.fetchall():
     if curs.fetchall():
@@ -44,9 +11,7 @@ def user_info_2(conn):
     else:
     else:
         plus2 = '<li><a href="/alarm">' + load_lang('alarm') + '</a></li>'
         plus2 = '<li><a href="/alarm">' + load_lang('alarm') + '</a></li>'
 
 
-    if custom()[2] != 0:
-        ip_user = '<a href="/w/user:' + ip + '">' + ip + '</a>'
-        
+    if custom()[2] != 0:        
         plus = '''
         plus = '''
             <li><a href="/logout">''' + load_lang('logout') + '''</a></li>
             <li><a href="/logout">''' + load_lang('logout') + '''</a></li>
             <li><a href="/change">''' + load_lang('user_setting') + '''</a></li>
             <li><a href="/change">''' + load_lang('user_setting') + '''</a></li>
@@ -54,9 +19,7 @@ def user_info_2(conn):
 
 
         plus2 += '<li><a href="/watch_list">' + load_lang('watchlist') + '</a></li>'
         plus2 += '<li><a href="/watch_list">' + load_lang('watchlist') + '</a></li>'
         plus3 = '<li><a href="/acl/user:' + url_pas(ip) + '">' + load_lang('user_document_acl') + '</a></li>'
         plus3 = '<li><a href="/acl/user:' + url_pas(ip) + '">' + load_lang('user_document_acl') + '</a></li>'
-    else:
-        ip_user = ip
-        
+    else:        
         plus = '''
         plus = '''
             <li><a href="/login">''' + load_lang('login') + '''</a></li>
             <li><a href="/login">''' + load_lang('login') + '''</a></li>
             <li><a href="/register">''' + load_lang('register') + '''</a></li>
             <li><a href="/register">''' + load_lang('register') + '''</a></li>
@@ -72,10 +35,8 @@ def user_info_2(conn):
         imp = [load_lang('user_tool'), wiki_set(), custom(), other2([0, 0])],
         imp = [load_lang('user_tool'), wiki_set(), custom(), other2([0, 0])],
         data = '''
         data = '''
             <h2>''' + load_lang('state') + '''</h2>
             <h2>''' + load_lang('state') + '''</h2>
-            <ul>
-                <li>''' + ip_user + ''' <a href="/record/''' + url_pas(ip) + '''">(''' + load_lang('record') + ''')</a></li>
-                <li>''' + load_lang('state') + ''' : ''' + acl + '''</li>
-            </ul>
+            <div id="get_user_info"></div>
+            <script>load_user_info("''' + ip + '''");</script>
             <br>
             <br>
             <h2>''' + load_lang('login') + '''</h2>
             <h2>''' + load_lang('login') + '''</h2>
             <ul>
             <ul>

+ 6 - 2
route/view_diff_data.py

@@ -3,8 +3,12 @@ from .tool.func import *
 def view_diff_data_2(conn, name):
 def view_diff_data_2(conn, name):
     curs = conn.cursor()
     curs = conn.cursor()
 
 
-    first = flask.request.args.get('first', '1')
-    second = flask.request.args.get('second', '1')
+    first = number_check(flask.request.args.get('first', '1'))
+    second = number_check(flask.request.args.get('second', '1'))
+
+    curs.execute("select title from history where title = ? and id = ? or id = ? and hide = 'O'", [name, first, second])
+    if curs.fetchall() and admin_check(6) != 1:
+        return re_error('/error/3')
 
 
     curs.execute("select data from history where id = ? and title = ?", [first, name])
     curs.execute("select data from history where id = ? and title = ?", [first, name])
     first_raw_data = curs.fetchall()
     first_raw_data = curs.fetchall()

+ 1 - 1
route/view_down.py

@@ -5,7 +5,7 @@ def view_down_2(conn, name):
 
 
     div = '<ul>'
     div = '<ul>'
 
 
-    curs.execute("select title from data where title like ?", ['%' + name + '/%'])
+    curs.execute("select title from data where title like ?", [name + '/%'])
     for data in curs.fetchall():
     for data in curs.fetchall():
         div += '<li><a href="/w/' + url_pas(data[0]) + '">' + data[0] + '</a></li>'
         div += '<li><a href="/w/' + url_pas(data[0]) + '">' + data[0] + '</a></li>'
         
         

+ 45 - 20
route/view_read.py

@@ -13,9 +13,11 @@ def view_read_2(conn, name):
     else:
     else:
         if not flask.request.args.get('from', None):
         if not flask.request.args.get('from', None):
             curs.execute("select title from back where link = ? and type = 'redirect'", [name])
             curs.execute("select title from back where link = ? and type = 'redirect'", [name])
-            redirect_data = curs.fetchall()
-            if redirect_data:
-                return redirect('/w/' + redirect_data[0][0] + '?from=' + name)
+            r_db = curs.fetchall()
+            if r_db:
+                r_data = link_fix(r_db[0][0])
+            
+                return redirect('/w/' + r_data[0] + '?from=' + name + r_data[1])
 
 
     curs.execute("select sub from rd where title = ? and not stop = 'O' order by date desc", [name])
     curs.execute("select sub from rd where title = ? and not stop = 'O' order by date desc", [name])
     if curs.fetchall():
     if curs.fetchall():
@@ -77,21 +79,7 @@ def view_read_2(conn, name):
     else:
     else:
         else_data = None
         else_data = None
 
 
-    m = re.search("^user:([^/]*)", name)
-    if m:
-        g = m.groups()
-        
-        curs.execute("select acl from user where id = ?", [g[0]])
-        test = curs.fetchall()
-        if test and test[0][0] != 'user':
-            acl = ' (' + load_lang('admin') + ')'
-        else:
-            if ban_check(g[0]) == 1:
-                sub += ' (' + load_lang('blocked') + ')'
-            else:
-                acl = ''
-
-    curs.execute("select dec from acl where title = ?", [name])
+    curs.execute("select decu from acl where title = ?", [name])
     data = curs.fetchall()
     data = curs.fetchall()
     if data:
     if data:
         acl += ' (' + load_lang('acl') + ')'
         acl += ' (' + load_lang('acl') + ')'
@@ -107,10 +95,38 @@ def view_read_2(conn, name):
 
 
     if end_data == 'HTTP Request 401.3':
     if end_data == 'HTTP Request 401.3':
         response_data = 401
         response_data = 401
-        end_data = '<h2>' + load_lang('error') + '</h2><ul><li>' + load_lang('authority_error') + '</li></ul>'
+        
+        curs.execute('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>'
+        else:
+            end_data = '<h2>' + load_lang('error') + '</h2><ul><li>' + load_lang('authority_error') + '</li></ul>'
     elif end_data == 'HTTP Request 404':
     elif end_data == 'HTTP Request 404':
         response_data = 404
         response_data = 404
-        end_data = '<h2>' + load_lang('error') + '</h2><ul><li>' + load_lang('decument_404_error') + '</li></ul>'
+        
+        curs.execute('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>'
+        else:
+            end_data = '<h2>' + load_lang('error') + '</h2><ul><li>' + load_lang('decument_404_error') + '</li></ul>'
+            
+        curs.execute('select ip, date, leng, send from history where title = ? order by id desc limit 3', [name])
+        sql_d = curs.fetchall()
+        if sql_d:
+            end_data += '<h2>' + load_lang('history') + '</h2><ul>'
+            for i in sql_d:
+                if re.search("\+", i[2]):
+                    leng = '<span style="color:green;">(' + i[2] + ')</span>'
+                elif re.search("\-", i[2]):
+                    leng = '<span style="color:red;">(' + i[2] + ')</span>'
+                else:
+                    leng = '<span style="color:gray;">(' + i[2] + ')</span>'
+            
+                end_data += '<li>' + i[1] + ' | ' + ip_pas(i[0]) + ' | ' + leng + (' | ' + i[3] if i[3] != '' else '') + '</li>'
+                
+            end_data += '<li><a href="/history/' + url_pas(name) + '">(...)</a></li></ul>'
     else:
     else:
         response_data = 200
         response_data = 200
     
     
@@ -168,6 +184,15 @@ def view_read_2(conn, name):
     
     
     div = adsense_code + '<div>' + div + '</div>'
     div = adsense_code + '<div>' + div + '</div>'
 
 
+    # 이 부분 개선 필요
+    match = re.search("^user:([^/]*)", name)
+    if match:
+        user_name = match.groups()[0]
+        div = '''
+            <div id="get_user_info"></div>
+            <script>load_user_info("''' + user_name + '''");</script>
+        ''' + div
+        
     return easy_minify(flask.render_template(skin_check(), 
     return easy_minify(flask.render_template(skin_check(), 
         imp = [flask.request.args.get('show', name), wiki_set(), custom(), other2([sub + acl, r_date])],
         imp = [flask.request.args.get('show', name), wiki_set(), custom(), other2([sub + acl, r_date])],
         data = div,
         data = div,

+ 7 - 2
route/watch_list.py

@@ -3,12 +3,17 @@ from .tool.func import *
 def watch_list_2(conn):
 def watch_list_2(conn):
     curs = conn.cursor()
     curs = conn.cursor()
 
 
-    div = 'limit : 10<hr class=\"main_hr\">'
+    div = 'Limit : 10<hr class=\"main_hr\">'
     
     
     if custom()[2] == 0:
     if custom()[2] == 0:
         return redirect('/login')
         return redirect('/login')
 
 
-    curs.execute("select title from scan where user = ?", [ip_check()])
+    ip = ip_check()
+
+    curs.execute("delete from scan where user = ? and title = ''", [ip])
+    conn.commit()
+
+    curs.execute("select title from scan where user = ?", [ip])
     data = curs.fetchall()
     data = curs.fetchall()
     for data_list in data:
     for data_list in data:
         div += '<li><a href="/w/' + url_pas(data_list[0]) + '">' + data_list[0] + '</a> <a href="/watch_list/' + url_pas(data_list[0]) + '">(' + load_lang('delete') + ')</a></li>'
         div += '<li><a href="/w/' + url_pas(data_list[0]) + '">' + data_list[0] + '</a> <a href="/watch_list/' + url_pas(data_list[0]) + '">(' + load_lang('delete') + ')</a></li>'

+ 2 - 2
version.json

@@ -1,7 +1,7 @@
 {
 {
     "master" : {
     "master" : {
-        "r_ver" : "v3.1.1-stable-04",
-        "c_ver" : "400001",
+        "r_ver" : "v3.1.2-stable-01",
+        "c_ver" : "400003",
         "s_ver" : "2"
         "s_ver" : "2"
     }, "stable" : {
     }, "stable" : {
         "r_ver" : "v3.1.1-stable-04",
         "r_ver" : "v3.1.1-stable-04",

+ 53 - 3
views/easter_egg.html

@@ -1,3 +1,53 @@
-<iframe style="width: 100%; height: 500px;" src="https://jcw87.github.io/c2-sans-fight/"></iframe>
-<br>
-<a id="out_link" href="https://jcw87.github.io/c2-sans-fight/">https://jcw87.github.io/c2-sans-fight/</a>
+<iframe width="560" height="315" src="https://www.youtube.com/embed/7wzZbLKnUuA" allowfullscreen></iframe>
+<hr class="main_hr">
+<pre>
+    Nagareteku toki no naka de demo kedarusa ga hora guruguru mawatte
+    Watashi kara hanareru kokoro mo mienai wa sou shiranai
+    
+    Jibun kara ugoku koto mo naku toki no sukima ni nagasare tsuzukete
+    Shiranai wa mawari no koto nado watashi wa watashi sore dake
+    
+    Yume miteru? Nani mo mitenai? Kataru mo muda na jibun no kotoba
+    Kanashimu nante tsukareru dake yo nani mo kanjizu sugoseba ii no
+    
+    Tomadou kotoba ataerarete mo jibun no kokoro tada uwa no sora
+    Moshi watashi kara ugoku no naraba subete kaeru no nara kuro ni suru
+    
+    Konna jibun ni mirai wa aru no? Konna sekai ni watashi wa iru no?
+    Ima setsunai no? Ima kanashii no? Jibun no koto mo wakaranai mama
+    
+    Ayumu koto sae tsukareru dake yo hito no koto nado shiri mo shinaiwa
+    Konna watashi mo kawareru no nara moshi kawareru no nara shiro ni naru?
+    
+    Nagareteku toki no naka de demo kedarusa ga hora guruguru mawatte
+    Watashi kara hanareru kokoro mo mienaiwa sou shiranai
+    
+    Jibun kara ugoku koto mo naku toki no sukima ni nagasare tsuzukete
+    Shiranai wa mawari no koto nado watashi wa watashi sore dake
+    
+    Yume miteru? Nani mo mitenai? Kataru mo muda na jibun no kotoba
+    Kanashimu nante tsukareru dake yo nani mo kanjizu sugoseba ii no
+    
+    Tomadou kotoba ataerarete mo jibun no kokoro tada uwa no sora
+    Moshi watashi kara ugoku no naraba subete kaeru no nara kuro ni suru
+    
+    Muda na jikan ni mirai wa aru no? Konna tokoro ni watashi wa iru no?
+    Watashi no koto o iitai naraba kotoba ni suru no nara "roku de nashi"
+    
+    Konna tokoro ni watashi wa iru no? Konna jikan ni watashi wa iru no?
+    Konna watashi mo kawareru no nara moshi kawareru no nara shiro ni naru?
+    
+    Ima yume miteru? Nani mo mitenai? Kataru mo muda na jibun no kotoba?
+    Kanashimu nante tsukareru dake yo nani mo kanjizu sugoseba ii no
+    
+    Tomadou kotoba ataerarete mo jibun no kokoro tada uwa no sora
+    Moshi watashi kara ugoku no naraba subete kaeru no nara kuro ni suru
+    
+    Ugoku no naraba ugoku no naraba subete kowasu wa subete kowasu wa
+    Kanashimu naraba kanashimu naraba watashi no kokoro shiroku kawareru?
+    
+    Anata no koto mo watashi no koto mo subete no koto mo mada shiranai no
+    Omoi mabuta wo aketa no naraba subete kowasu no nara kuro ni nare!!!
+
+    <a href="https://touhou.fandom.com/wiki/Lyrics:_Bad_Apple!!">Ref - Touhou wiki</a>
+</pre>    

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

@@ -19,7 +19,7 @@ input[type="checkbox"] { width: auto; }
 #toron_color_red { background: indianred; }
 #toron_color_red { background: indianred; }
 #toron_color_grey { background: gainsboro; }
 #toron_color_grey { background: gainsboro; }
 #cate { border: 1px solid; padding: 5px; }
 #cate { border: 1px solid; padding: 5px; }
-blockquote { border: 1px solid; padding: 15px; margin: 0; margin-top: 10px; }
+blockquote { border: 1px solid; padding: 15px; margin: 0; margin-top: 10px; display: inline-block; }
 img, iframe { max-width: 100%; }
 img, iframe { max-width: 100%; }
 pre { border: 1px solid; padding: 10px; white-space: pre-wrap; }
 pre { border: 1px solid; padding: 10px; white-space: pre-wrap; }
 #in { margin-left: 20px; }
 #in { margin-left: 20px; }
@@ -37,4 +37,5 @@ hr.main_hr { border: none; }
 .foot_plus { background: gainsboro; }
 .foot_plus { background: gainsboro; }
 #toc_title { font-size: 18px; }
 #toc_title { font-size: 18px; }
 blockquote { background-image: url(/views/acme/img/quote.png); background-position: calc(100% - 10px) 10px; background-repeat: no-repeat; background-size: 25px; }
 blockquote { background-image: url(/views/acme/img/quote.png); background-position: calc(100% - 10px) 10px; background-repeat: no-repeat; background-size: 25px; }
-#admin_log_search { width: 100px; }
+#admin_log_search { width: 100px; }
+@media (max-width: 768px) { table { min-width: 100%; }}

+ 0 - 19
views/main_css/js/do_preview.js

@@ -1,19 +0,0 @@
-function do_preview(name) {
-    var o_data = document.getElementById('content');
-    var p_data = document.getElementById('see_preview');
-
-    var s_data = new FormData();
-    s_data.append('data', o_data.value);
-
-    var url = "/api/w/" + name;
-    
-    var xhr = new XMLHttpRequest();
-    xhr.open("POST", url, true);
-    xhr.send(s_data);
-
-    xhr.onreadystatechange = function() {
-        if(this.readyState === 4 && this.status === 200) {
-            p_data.innerHTML = JSON.parse(this.responseText)['data'];
-        }
-    }
-}

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

@@ -0,0 +1,34 @@
+function load_preview(name) {
+    var o_data = document.getElementById('content');
+    var p_data = document.getElementById('see_preview');
+
+    var s_data = new FormData();
+    s_data.append('data', o_data.value);
+
+    var url = "/api/w/" + encodeURI(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) {
+            p_data.innerHTML = JSON.parse(xhr.responseText)['data'];
+
+            xhr_2.onreadystatechange = function() {
+                if(xhr_2.readyState === 4 && xhr_2.status === 200) {
+                    markup = JSON.parse(xhr_2.responseText)['markup'];
+
+                    if(markup === 'markdown') {
+                        render_markdown();
+                    }
+                }
+            }
+        }
+    }
+}

+ 15 - 0
views/main_css/js/load_user_info.js

@@ -0,0 +1,15 @@
+function load_user_info(name) {
+    var n_ver = document.getElementById('get_user_info');
+
+    var url = "/api/user_info/" + encodeURI(name) + "?render=1";
+    
+    var xhr = new XMLHttpRequest();
+    xhr.open("GET", url, true);
+    xhr.send(null);
+
+    xhr.onreadystatechange = function() {
+        if(this.readyState === 4 && this.status === 200) {
+            n_ver.innerHTML += JSON.parse(this.responseText)['data'];
+        }
+    }
+}

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

@@ -0,0 +1,10 @@
+function render_markdown() {
+    data = document.getElementById('render_contect').innerHTML;
+
+    data = data.replace(/\*\*((?:(?!\*\*).)+)\*\*/, '<b>$1</b>');
+    data = data.replace(/__((?:(?!__).)+)__/, '<b>$1</b>');
+    data = data.replace(/\*((?:(?!\*).)+)\*/, '<i>$1</i>');
+    data = data.replace(/_((?:(?!_).)+)_/, '<i>$1</i>');
+    
+    document.getElementById('render_contect').innerHTML = data;
+}

+ 23 - 0
views/main_css/js/topic_list_load.js

@@ -0,0 +1,23 @@
+function topic_list_load(name, sub, s_num, where) {
+    var o_data = document.getElementById(where);
+    var url = "/api/topic/" + encodeURI(name) + "/sub/" + encodeURI(sub) + "?render=1&num=" + s_num;
+    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) {
+            t_data = JSON.parse(this.responseText);
+            for(key in t_data) {
+                n_data += t_data[key]['data'];
+                num = key;
+            }
+            
+            o_data.innerHTML = n_data;
+        }
+    }
+    
+}

+ 0 - 31
views/main_css/js/topic_load.js

@@ -1,31 +0,0 @@
-function topic_load(name, sub, num) {
-    var test = setInterval(function() {
-        var url = "/api/topic/" + name + "/sub/" + sub + "?num=" + num;
-        var doc_data = document.getElementById("plus");
-
-        var xhr = new XMLHttpRequest();
-        xhr.open("GET", url, true);
-        xhr.send(null);
-
-        xhr.onreadystatechange = function() {
-            if(this.readyState === 4 && this.status === 200) {
-                if(this.responseText) {
-                    doc_data.innerHTML += '<hr class="main_hr">(New)<hr class="main_hr">';
-
-                    // https://programmingsummaries.tistory.com/379
-                    var options = {
-                        body: 'New topic'
-                    }
-                   
-                    var notification = new Notification("openNAMU", options);
-                    
-                    setTimeout(function () {
-                        notification.close();
-                    }, 5000);
-
-                    clearInterval(test);
-                }
-            }
-        }
-    }, 2000);
-}

+ 45 - 0
views/main_css/js/topic_main_load.js

@@ -0,0 +1,45 @@
+function topic_main_load(name, sub, s_num) {
+    var o_data = document.getElementById('main_topic');
+    if(s_num) {
+        var url = "/api/topic/" + name + "/sub/" + sub + "?render=1&num=" + s_num;
+    } else {
+        var url = "/api/topic/" + name + "/sub/" + sub + "?render=1";
+    }
+    var url_2 = "/api/markup";
+    var n_data = "";
+    var num = 1;
+    
+    var xhr = new XMLHttpRequest();
+    xhr.open("GET", url, true);
+    xhr.send(null);
+
+    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) {
+            t_data = JSON.parse(xhr.responseText);
+            for(key in t_data) {
+                n_data += t_data[key]['data'];
+                num = key;
+            }
+            
+            o_data.innerHTML = n_data;
+            if(!s_num) {
+                topic_plus_load(name, sub, String(Number(num) + 1));
+            }
+
+            xhr_2.onreadystatechange = function() {
+                if(xhr_2.readyState === 4 && xhr_2.status === 200) {
+                    markup = JSON.parse(xhr_2.responseText)['markup'];
+
+                    if(markup === 'markdown') {
+                        render_markdown();
+                    }
+                }
+            }
+        }
+    }
+    
+}

+ 38 - 0
views/main_css/js/topic_plus_load.js

@@ -0,0 +1,38 @@
+function topic_plus_load(name, sub, num) {
+    var test = setInterval(function() {
+        var url = "/api/topic/" + encodeURI(name) + "/sub/" + encodeURI(sub) + "?num=" + num + "&render=1";
+        var p_data = document.getElementById("plus_topic");
+        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') {                
+                t_data = JSON.parse(this.responseText);
+                for(key in t_data) {
+                    n_data += t_data[key]['data'];
+                    n_num = key;
+                }
+                
+                p_data.innerHTML += n_data;
+
+                // https://programmingsummaries.tistory.com/379
+                var options = {
+                    body: 'New ' + n_num + ' topic'
+                }
+               
+                var notification = new Notification("openNAMU", options);
+                
+                setTimeout(function () {
+                    notification.close();
+                }, 5000);
+
+                topic_plus_load(name, sub, String(Number(num) + 1));
+                clearInterval(test);
+            }
+        }
+    }, 2000);
+}

+ 1 - 1
views/main_css/js/reload.js → views/main_css/js/topic_reload.js

@@ -1,3 +1,3 @@
-function reload() {
+function topic_reload() {
     location.href.endsWith('#reload') ? location.reload(true) : location.href = '#reload';
     location.href.endsWith('#reload') ? location.reload(true) : location.href = '#reload';
 }
 }

+ 24 - 0
views/main_css/js/topic_top_load.js

@@ -0,0 +1,24 @@
+function topic_top_load(name, sub) {
+    var o_data = document.getElementById('top_topic');
+    var url = "/api/topic/" + encodeURI(name) + "/sub/" + encodeURI(sub) + "?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) {
+            t_data = JSON.parse(this.responseText);
+            for(key in t_data) {
+                n_data += t_data[key]['data'];
+                num = key;
+            }
+            
+            o_data.innerHTML = n_data;
+            topic_main_load(name, sub, null);
+        }
+    }
+    
+}

+ 0 - 2
views/neo_yousoro/css/main.css

@@ -375,8 +375,6 @@ blockquote {
     padding: 1em calc(2em + 25px) 1em 1em;
     padding: 1em calc(2em + 25px) 1em 1em;
     margin: 1em 0em 0em;
     margin: 1em 0em 0em;
     background: #eeeeee;
     background: #eeeeee;
-    display: block;
     border: 2px dashed #ccc;
     border: 2px dashed #ccc;
     border-left: 5px solid skyblue;
     border-left: 5px solid skyblue;
-    font-size: 14px;
 }
 }