Selaa lähdekoodia

Merge pull request #868 from 2du/master

stable
잉여개발기 (SPDV) 6 vuotta sitten
vanhempi
sitoutus
f96473678d
70 muutettua tiedostoa jossa 1771 lisäystä ja 1705 poistoa
  1. 6 2
      .gitignore
  2. 88 53
      app.py
  3. 0 24
      data/oauthsettings.json
  4. 140 19
      emergency_tool.py
  5. 66 37
      language/en-US.json
  6. 3 3
      language/help_tool.py
  7. 52 24
      language/ko-KR.json
  8. 1 1
      readme-en.md
  9. 1 1
      readme.md
  10. 1 0
      requirements.txt
  11. 9 0
      route/api_image_view.py
  12. 30 6
      route/api_skin_info.py
  13. 9 2
      route/api_topic_sub.py
  14. 5 1
      route/api_user_info.py
  15. 8 1
      route/api_w.py
  16. 10 0
      route/application_submitted.py
  17. 108 0
      route/applications.py
  18. 11 4
      route/edit.py
  19. 6 4
      route/edit_delete.py
  20. 5 3
      route/edit_many_delete.py
  21. 85 29
      route/edit_move.py
  22. 6 3
      route/edit_req.py
  23. 8 12
      route/func_upload.py
  24. 23 0
      route/give_delete_admin_group.py
  25. 34 11
      route/give_user_check.py
  26. 1 8
      route/inter_wiki.py
  27. 7 2
      route/list_give.py
  28. 2 2
      route/list_old_page.py
  29. 35 6
      route/login_check_key.py
  30. 1 2
      route/login_need_email.py
  31. 75 18
      route/login_register.py
  32. 1 1
      route/main_error_404.py
  33. 7 4
      route/main_file.py
  34. 4 1
      route/main_image_view.py
  35. 16 16
      route/main_manager.py
  36. 10 1
      route/main_views.py
  37. 1 1
      route/recent_changes.py
  38. 2 2
      route/recent_discuss.py
  39. 10 9
      route/search_deep.py
  40. 168 52
      route/setting.py
  41. 0 100
      route/setting_oauth.py
  42. 129 99
      route/tool/func.py
  43. 1 1
      route/tool/init.py
  44. 22 33
      route/tool/mark.py
  45. 0 14
      route/tool/set_mark/markdown.py
  46. 250 286
      route/tool/set_mark/namumark.py
  47. 0 0
      route/tool/set_mark/namumark_backlink.py
  48. 9 25
      route/tool/set_mark/tool.py
  49. 1 1
      route/topic.py
  50. 1 1
      route/user_custom_head_view.py
  51. 24 2
      route/view_diff_data.py
  52. 42 19
      route/view_read.py
  53. 4 4
      version.json
  54. 4 2
      views/main_css/css/main.css
  55. 3 2
      views/main_css/js/do_insert_data.js
  56. 5 13
      views/main_css/js/do_open_foot.js
  57. 0 33
      views/main_css/js/load_include.js
  58. 75 0
      views/main_css/js/load_namumark.js
  59. 1 7
      views/main_css/js/load_preview.js
  60. 138 0
      views/main_css/js/load_topic.js
  61. 0 10
      views/main_css/js/render_markdown.js
  62. 0 531
      views/main_css/js/render_namumark.js
  63. 0 23
      views/main_css/js/topic_list_load.js
  64. 0 49
      views/main_css/js/topic_main_load.js
  65. 0 57
      views/main_css/js/topic_plus_load.js
  66. 0 24
      views/main_css/js/topic_top_load.js
  67. 4 0
      views/marisa/css/dark.css
  68. 1 2
      views/marisa/index.html
  69. 1 1
      views/marisa/info.json
  70. 1 1
      views/marisa/js/skin_set.js

+ 6 - 2
.gitignore

@@ -1,15 +1,19 @@
 __pycache__
 /app_session
+
 data/set.json
 data/mysql.json
-404.html
+data/oauthsettings.json
+
+images
 .vscode
 
 *.db
 *.db-journal
 
-images
 robots.txt
+custom.py
+404.html
 
 views/liberty
 views/buma

+ 88 - 53
app.py

@@ -29,6 +29,9 @@ while 1:
                 print('----')
                 raise
         else:
+            print('DB name : ' + set_data['db'])
+            print('DB type : ' + set_data['db_type'])
+
             break
     except:
         if os.getenv('NAMU_DB') != None or os.getenv('NAMU_DB_TYPE') != None:
@@ -37,12 +40,15 @@ while 1:
                 "db_type" : os.getenv('NAMU_DB_TYPE') if os.getenv('NAMU_DB_TYPE') else 'sqlite'
             }
 
+            print('DB name : ' + set_data['db'])
+            print('DB type : ' + set_data['db_type'])
+
             break
         else:
             new_json = ['', '']
             normal_db_type = ['sqlite', 'mysql']
 
-            print('DB type (sqlite, mysql) : ', end = '')
+            print('DB type (sqlite) [sqlite, mysql] : ', end = '')
             new_json[0] = str(input())
             if new_json[0] == '' or not new_json[0] in normal_db_type:
                 new_json[0] = 'sqlite'
@@ -53,8 +59,8 @@ while 1:
                 if f_src:
                     all_src += [f_src.groups()[0]]
 
-            if all_src != []:
-                print('DB name (' + ', '.join(all_src) + ') : ', end = '')
+            if all_src != [] and new_json[0] != 'mysql':
+                print('DB name (data) [' + ', '.join(all_src) + '] : ', end = '')
             else:
                 print('DB name (data) : ', end = '')
 
@@ -69,9 +75,6 @@ while 1:
 
             break
 
-print('DB name : ' + set_data['db'])
-print('DB type : ' + set_data['db_type'])
-
 db_data_get(set_data['db_type'])
 
 if set_data['db_type'] == 'mysql':
@@ -115,32 +118,8 @@ else:
     conn = sqlite3.connect(set_data['db'] + '.db', check_same_thread = False)
     curs = conn.cursor()
 
-if os.path.exists(set_data['db'] + '.db'):
-    setup_tool = 0
-else:
-    setup_tool = 1
-
 load_conn(conn)
 
-logging.basicConfig(level = logging.ERROR)
-
-app = flask.Flask(__name__, template_folder = './')
-app.config['JSON_AS_ASCII'] = False
-
-flask_reggie.Reggie(app)
-
-compress = flask_compress.Compress()
-compress.init_app(app)
-
-class EverythingConverter(werkzeug.routing.PathConverter):
-    regex = '.*?'
-
-app.jinja_env.filters['md5_replace'] = md5_replace
-app.jinja_env.filters['load_lang'] = load_lang
-app.jinja_env.filters['cut_100'] = cut_100
-
-app.url_map.converters['everything'] = EverythingConverter
-
 create_data = {}
 create_data['all_data'] = [
     'data',
@@ -165,6 +144,7 @@ create_data['all_data'] = [
     'inter',
     'html_filter',
     'oauth_conn',
+    'user_application'
 ]
 for i in create_data['all_data']:
     try:
@@ -175,25 +155,26 @@ for i in create_data['all_data']:
         except:
             curs.execute(db_change("alter table " + i + " add test longtext default ''"))
 
-if setup_tool == 0:
-    try:
-        curs.execute(db_change('select data from other where name = "ver"'))
-        ver_set_data = curs.fetchall()
-        if not ver_set_data:
+setup_tool = 0
+try:
+    curs.execute(db_change('select data from other where name = "ver"'))
+    ver_set_data = curs.fetchall()
+    if not ver_set_data:
+        setup_tool = 2
+    else:
+        if int(version_list['master']['c_ver']) > int(ver_set_data[0][0]):
             setup_tool = 1
-        else:
-            if version_list['master']['c_ver'] > ver_set_data[0][0]:
-                setup_tool = 1
-    except:
-        setup_tool = 1
+except:
+    setup_tool = 2
 
 if setup_tool != 0:
     create_data['data'] = ['title', 'data']
-    create_data['cache_data'] = ['title', 'data']
+    create_data['cache_data'] = ['title', 'data', 'id']
     create_data['history'] = ['id', 'title', 'data', 'date', 'ip', 'send', 'leng', 'hide', 'type']
     create_data['rd'] = ['title', 'sub', 'date', 'band', 'stop', 'agree']
     create_data['user'] = ['id', 'pw', 'acl', 'date', 'encode']
     create_data['user_set'] = ['name', 'id', 'data']
+    create_data['user_application'] = ['id', 'pw', 'date', 'encode', 'question', 'answer', 'ip', 'ua', 'token', 'email']
     create_data['ban'] = ['block', 'end', 'why', 'band', 'login']
     create_data['topic'] = ['id', 'title', 'sub', 'data', 'date', 'ip', 'block', 'top', 'code']
     create_data['rb'] = ['block', 'end', 'today', 'blocker', 'why', 'band']
@@ -223,12 +204,37 @@ if setup_tool != 0:
             except:
                 pass
 
-    update()
+    if setup_tool == 1:
+        update(int(ver_set_data[0][0]))
+    else:
+        set_init()
+
+curs.execute(db_change('delete from other where name = "ver"'))
+curs.execute(db_change('insert into other (name, data) values ("ver", ?)'), [version_list['master']['c_ver']])
+conn.commit()
 
 # Init
+logging.basicConfig(level = logging.ERROR)
+
+app = flask.Flask(__name__, template_folder = './')
+app.config['JSON_AS_ASCII'] = False
+
+flask_reggie.Reggie(app)
+
+compress = flask_compress.Compress()
+compress.init_app(app)
+
+class EverythingConverter(werkzeug.routing.PathConverter):
+    regex = '.*?'
+
+app.jinja_env.filters['md5_replace'] = md5_replace
+app.jinja_env.filters['load_lang'] = load_lang
+app.jinja_env.filters['cut_100'] = cut_100
+
+app.url_map.converters['everything'] = EverythingConverter
+
 curs.execute(db_change('select name from alist where acl = "owner"'))
 if not curs.fetchall():
-    curs.execute(db_change('delete from alist where name = "owner"'))
     curs.execute(db_change('insert into alist (name, acl) values ("owner", "owner")'))
 
 if not os.path.exists(app_var['path_data_image']):
@@ -273,9 +279,6 @@ if not adsense_result:
     curs.execute(db_change('insert into other (name, data) values ("adsense", "False")'))
     curs.execute(db_change('insert into other (name, data) values ("adsense_code", "")'))
 
-curs.execute(db_change('delete from other where name = "ver"'))
-curs.execute(db_change('insert into other (name, data) values ("ver", ?)'), [version_list['master']['c_ver']])
-
 if set_data['db_type'] == 'sqlite':
     def back_up():
         print('----')
@@ -315,12 +318,18 @@ if set_data['db_type'] == 'mysql':
 
     mysql_dont_off()
 
+
 curs.execute(db_change('select data from other where name = "count_all_title"'))
 if not curs.fetchall():
     curs.execute(db_change('insert into other (name, data) values ("count_all_title", "0")'))
 
 conn.commit()
 
+if os.path.exists('custom.py'):
+    from custom import custom_run
+
+    custom_run(conn, app)
+
 # Func
 @app.route('/del_alarm')
 def alarm_del():
@@ -364,6 +373,10 @@ def list_acl():
 def give_admin_groups(name = None):
     return give_admin_groups_2(conn, name)
 
+@app.route('/delete_admin_group/<name>', methods=['POST', 'GET'])
+def delete_admin_group(name = None):
+    return delete_admin_group_2(conn, name)
+
 @app.route('/admin_list')
 def list_admin():
     return list_admin_2(conn)
@@ -396,10 +409,6 @@ def server_restart():
 def server_now_update():
     return server_now_update_2(conn, version_list['master']['r_ver'])
 
-@app.route('/oauth_setting', methods=['GET', 'POST'])
-def setting_oauth():
-    return setting_oauth_2(conn)
-
 @app.route('/adsense_setting', methods=['GET', 'POST'])
 def setting_adsense():
     return setting_adsense_2(conn)
@@ -628,6 +637,14 @@ def main_image_view(name = None):
 def main_skin_set():
     return main_skin_set_2(conn)
 
+@app.route('/application_submitted')
+def application_submitted():
+    return application_submitted_2(conn)
+
+@app.route('/applications', methods = ['POST', 'GET'])
+def applications():
+    return applications_2(conn)
+
 # API
 @app.route('/api/w/<everything:name>', methods=['POST', 'GET'])
 def api_w(name = ''):
@@ -670,6 +687,10 @@ def api_recent_change():
 def api_sha224(name = 'test'):
     return api_sha224_2(conn, name)
 
+@app.route('/api/image/<name>')
+def api_image_view(name = ''):
+    return api_image_view_2(conn, name, app_var)
+
 # File
 @app.route('/views/<everything:name>')
 def main_views(name = None):
@@ -689,7 +710,21 @@ app.wsgi_app = werkzeug.debug.DebuggedApplication(app.wsgi_app, True)
 app.debug = True
 
 if __name__ == "__main__":
-    http_server = tornado.httpserver.HTTPServer(tornado.wsgi.WSGIContainer(app))
-    http_server.listen(server_set['port'], address = server_set['host'])
+    try:
+        http_server = tornado.httpserver.HTTPServer(tornado.wsgi.WSGIContainer(app))
+        http_server.listen(server_set['port'], address = server_set['host'])
 
-    tornado.ioloop.IOLoop.instance().start()
+        tornado.ioloop.IOLoop.instance().start()
+    except Exception as e:
+        if sys.platform == 'win32':
+            try:
+                asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
+                tornado.ioloop.IOLoop.instance().start()
+            except Exception as e:
+                print('----')
+                print(e)
+                raise
+        else:
+            print('----')
+            print(e)
+            raise

+ 0 - 24
data/oauthsettings.json

@@ -1,24 +0,0 @@
-{
-    "_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 연결을 지원해야 합니다.",
-        "support" : ["discord", "facebook", "naver", "kakao"]
-    },
-    "publish_url" : "https://",
-    "discord" : {
-        "client_id" : "",
-        "client_secret" : ""
-    },
-    "facebook" : {
-        "client_id" : "",
-        "client_secret" : ""
-    },
-    "naver" : {
-        "client_id" : "",
-        "client_secret" : ""
-    },
-    "kakao" : {
-        "client_id" : "",
-        "client_secret" : ""
-    }
-}

+ 140 - 19
emergency_tool.py

@@ -1,9 +1,12 @@
+import time
 from route.tool.func import *
 
+version_list = json.loads(open('version.json', encoding='utf8').read())
+
 # DB
 while 1:
     try:
-        set_data = json.loads(open('data/set.json').read())
+        set_data = json.loads(open('data/set.json', encoding='utf8').read())
         if not 'db_type' in set_data:
             try:
                 os.remove('data/set.json')
@@ -12,6 +15,9 @@ while 1:
                 print('----')
                 raise
         else:
+            print('DB name : ' + set_data['db'])
+            print('DB type : ' + set_data['db_type'])
+
             break
     except:
         if os.getenv('NAMU_DB') != None or os.getenv('NAMU_DB_TYPE') != None:
@@ -20,12 +26,15 @@ while 1:
                 "db_type" : os.getenv('NAMU_DB_TYPE') if os.getenv('NAMU_DB_TYPE') else 'sqlite'
             }
 
+            print('DB name : ' + set_data['db'])
+            print('DB type : ' + set_data['db_type'])
+
             break
         else:
             new_json = ['', '']
             normal_db_type = ['sqlite', 'mysql']
 
-            print('DB type (sqlite, mysql) : ', end = '')
+            print('DB type (sqlite) [sqlite, mysql] : ', end = '')
             new_json[0] = str(input())
             if new_json[0] == '' or not new_json[0] in normal_db_type:
                 new_json[0] = 'sqlite'
@@ -36,8 +45,8 @@ while 1:
                 if f_src:
                     all_src += [f_src.groups()[0]]
 
-            if all_src != []:
-                print('DB name (' + ', '.join(all_src) + ') : ', end = '')
+            if all_src != [] and new_json[0] != 'mysql':
+                print('DB name (data) [' + ', '.join(all_src) + '] : ', end = '')
             else:
                 print('DB name (data) : ', end = '')
 
@@ -45,21 +54,18 @@ while 1:
             if new_json[1] == '':
                 new_json[1] = 'data'
 
-            with open('data/set.json', 'w') as f:
+            with open('data/set.json', 'w', encoding='utf8') as f:
                 f.write('{ "db" : "' + new_json[1] + '", "db_type" : "' + new_json[0] + '" }')
 
-            set_data = json.loads(open('data/set.json').read())
+            set_data = json.loads(open('data/set.json', encoding='utf8').read())
 
             break
 
-print('DB name : ' + set_data['db'])
-print('DB type : ' + set_data['db_type'])
-
 db_data_get(set_data['db_type'])
 
 if set_data['db_type'] == 'mysql':
     try:
-        set_data_mysql = json.loads(open('data/mysql.json').read())
+        set_data_mysql = json.loads(open('data/mysql.json', encoding='utf8').read())
     except:
         new_json = ['', '']
 
@@ -75,10 +81,10 @@ if set_data['db_type'] == 'mysql':
             if new_json[1] != '':
                 break
 
-        with open('data/mysql.json', 'w') as f:
+        with open('data/mysql.json', 'w', encoding='utf8') as f:
             f.write('{ "user" : "' + new_json[0] + '", "password" : "' + new_json[1] + '" }')
 
-        set_data_mysql = json.loads(open('data/mysql.json').read())
+        set_data_mysql = json.loads(open('data/mysql.json', encoding='utf8').read())
 
     conn = pymysql.connect(
         host = 'localhost',
@@ -100,6 +106,96 @@ else:
 
 load_conn(conn)
 
+create_data = {}
+create_data['all_data'] = [
+    'data',
+    'cache_data',
+    'history',
+    'rd',
+    'user',
+    'user_set',
+    'ban',
+    'topic',
+    'rb',
+    'back',
+    'custom',
+    'other',
+    'alist',
+    're_admin',
+    'alarm',
+    'ua_d',
+    'filter',
+    'scan',
+    'acl',
+    'inter',
+    'html_filter',
+    'oauth_conn',
+    'user_application'
+]
+for i in create_data['all_data']:
+    try:
+        curs.execute(db_change('select test from ' + i + ' limit 1'))
+    except:
+        try:
+            curs.execute(db_change('create table ' + i + '(test longtext)'))
+        except:
+            curs.execute(db_change("alter table " + i + " add test longtext default ''"))
+
+setup_tool = 0
+try:
+    curs.execute(db_change('select data from other where name = "ver"'))
+    ver_set_data = curs.fetchall()
+    if not ver_set_data:
+        setup_tool = 1
+    else:
+        if int(version_list['master']['c_ver']) > int(ver_set_data[0][0]):
+            setup_tool = 1
+except:
+    setup_tool = 1
+
+if setup_tool != 0:
+    create_data['data'] = ['title', 'data']
+    create_data['cache_data'] = ['title', 'data']
+    create_data['history'] = ['id', 'title', 'data', 'date', 'ip', 'send', 'leng', 'hide', 'type']
+    create_data['rd'] = ['title', 'sub', 'date', 'band', 'stop', 'agree']
+    create_data['user'] = ['id', 'pw', 'acl', 'date', 'encode']
+    create_data['user_set'] = ['name', 'id', 'data']
+    create_data['user_application'] = ['id', 'pw', 'date', 'encode', 'question', 'answer', 'ip', 'ua', 'token', 'email']
+    create_data['ban'] = ['block', 'end', 'why', 'band', 'login']
+    create_data['topic'] = ['id', 'title', 'sub', 'data', 'date', 'ip', 'block', 'top', 'code']
+    create_data['rb'] = ['block', 'end', 'today', 'blocker', 'why', 'band']
+    create_data['back'] = ['title', 'link', 'type']
+    create_data['custom'] = ['user', 'css']
+    create_data['other'] = ['name', 'data', 'coverage']
+    create_data['alist'] = ['name', 'acl']
+    create_data['re_admin'] = ['who', 'what', 'time']
+    create_data['alarm'] = ['name', 'data', 'date']
+    create_data['ua_d'] = ['name', 'ip', 'ua', 'today', 'sub']
+    create_data['filter'] = ['name', 'regex', 'sub']
+    create_data['scan'] = ['user', 'title']
+    create_data['acl'] = ['title', 'decu', 'dis', 'view', 'why']
+    create_data['inter'] = ['title', 'link', 'icon']
+    create_data['html_filter'] = ['html', 'kind', 'plus']
+    create_data['oauth_conn'] = ['provider', 'wiki_id', 'sns_id', 'name', 'picture']
+
+    for create_table in create_data['all_data']:
+        for create in create_data[create_table]:
+            try:
+                curs.execute(db_change('select ' + create + ' from ' + create_table + ' limit 1'))
+            except:
+                curs.execute(db_change("alter table " + create_table + " add " + create + " longtext default ''"))
+
+            try:
+                curs.execute(db_change('create index index_' + create_table + '_' + create + ' on ' + create_table + '(' + create + ')'))
+            except:
+                pass
+
+    update()
+
+curs.execute(db_change('delete from other where name = "ver"'))
+curs.execute(db_change('insert into other (name, data) values ("ver", ?)'), [version_list['master']['c_ver']])
+conn.commit()
+
 # Main
 print('----')
 print('1. Backlink reset')
@@ -120,19 +216,44 @@ print('Select : ', end = '')
 what_i_do = input()
 
 if what_i_do == '1':
-    curs.execute(db_change("delete from back"))
-    conn.commit()
+    print('----')
+    print('All delete (Y) [Y, N] : ', end = '')
+    go_num = input()
+    if not go_num == 'N':
+        curs.execute(db_change("delete from back"))
+        conn.commit()
+
+    print('----')
+    print('Count (100) : ', end = '')
+    try:
+        go_num = int(input())
+    except:
+        go_num = 100
 
-    curs.execute(db_change("select title, data from data"))
-    data = curs.fetchall()
     num = 0
 
-    for test in data:
+    print('----')
+    print('Load...')
+
+    curs.execute(db_change("select title from data d where not exists (select title from back where link = d.title)"))
+    title = curs.fetchall()
+
+    print('----')
+    print('Rest : ' + str(len(title)))
+    time.sleep(1)
+    print('----')
+
+    for name in title:
         num += 1
+        if num % go_num == 0:
+            print(str(num) + ' : ' + name[0])
+
         if num % 100 == 0:
-            print(num)
+            conn.commit()
 
-        render_do(test[0], test[1], 1, None)
+        curs.execute(db_change("select data from data where title = ?"), [name[0]])
+        data = curs.fetchall()
+        render_do(name[0], data[0][0], 3, None)
 elif what_i_do == '2':
     curs.execute(db_change("delete from other where name = 'recaptcha'"))
     curs.execute(db_change("delete from other where name = 'sec_re'"))

+ 66 - 37
language/en-US.json

@@ -97,6 +97,7 @@
         "view" : "View",
         "content" : "Content",
         "off" : "Off",
+        "delete_admin_group": "Delete admin group",
         "_comment_1.1_" : "Time",
             "second" : "Second(s)",
             "hour" : "Hour(s)",
@@ -106,7 +107,7 @@
             "end" : "End",
         "_comment_1.2_" : "User",
             "user" : "User",
-            "admin" : "Admin",
+            "admin" : "Administrator",
             "owner" : "Owner",
             "ip" : "IP",
             "member" : "Member",
@@ -124,15 +125,15 @@
         "recent_change" : "Recently edit(s)",
         "edit_filter" : "Contents filter",
         "recent_ban" : "Recently Block(s)",
-        "load" : "Import another document",
+        "load" : "Load another document",
         "edit_filter_rule" : "Contents filter rule",
-        "move_history" : "History of move",
+        "move_history" : "History of moveing",
         "other_tool" : "Other tools",
         "admin_tool" : "Administrator[s] tools",
         "check_user" : "Check user[s] login history",
         "compare_target" : "Comparison target name",
         "authorize" : "Authorize",
-        "indexing" : "DB Indexing",
+        "indexing" : "Database Indexing",
         "hide_release" : "Unhide",
         "pinned_release" : "Unpinned",
         "ban_release" : "Unblock",
@@ -145,7 +146,7 @@
         "connection" : "Connection",
         "new_connection" : "Connect...",
         "user_setting" : "User settings",
-        "now_password" : "Now password",
+        "now_password" : "Current password",
         "new_password" : "New password",
         "password_confirm" : "Password confirm",
         "oauth_connection" : "Oauth Connection",
@@ -161,47 +162,55 @@
         "encryption_method" : "Encryption method",
         "check_key" : "Check authentication key",
         "reset_user_ok" : "Check Success",
-        "name_or_ip_or_regex" : "ID or IP or Regex",
+        "name_or_ip_or_regex" : "Username or IP or Regex",
         "ban_period" : "Period to block",
         "not_sure" : "Not sure",
         "use_push_alarm" : "Enable Push Notification",
         "edit_button_paragraph" : "Paragraph",
-        "password_change" : "Password change",
+        "password_change" : "Change password",
         "email_change" : "Change email",
         "acl_change" : "Change document[s] ACL",
         "user_tool" : "User[s] tools",
         "skin_info" : "Skin information",
-        "closed_discussion" : "Closed discussion",
-        "agreed_discussion" : "Agreed discussion",
+        "closed_discussion" : "Closed discussions",
+        "agreed_discussion" : "Agreed discussions",
         "history_delete" : "Delete history",
         "direct_input" : "Direct input",
         "acl_record" : "ACL record",
         "last_edit_time" : "Last edited time",
-        "admin_group" : "Admin groups",
-        "topic_setting" : "Topic settings",
+        "admin_group" : "Administrator groups",
+        "topic_setting" : "Discussion settings",
         "old_page" : "Old decument(s)",
         "skin_set" : "Skin setting(s)",
-        "many_delete" : "Bulk delete",
+        "many_delete" : "Document bulk delete",
         "edit_req" : "Edit request",
         "edit_req_check" : "Check edit request",
+        "accept_edit_request" : "Accept edit request",
         "history_add" : "Add history",
+        "all_register_num" : "The number of application forms",
+        "replace_move" : "Reversing documents",
+        "merge_move" : "Merging documents",
+        "add_admin_group" : "Add administrator groups",
+        "add_watchlist" : "Add watchlist",
+        "blocked_user" : "Blocked user",
+        "blocked_admin" : "Blocked administrator",
         "_comment_2.1_" : "Filter",
             "_comment_2.1.1_" : "List",
                 "interwiki_list" : "Interwiki(s) list",
                 "email_filter_list" : "Email filter(s) list",
-                "id_filter_list" : "ID filter(s) list",
+                "id_filter_list" : "Username filter(s) list",
                 "edit_filter_list" : "Contents 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",
-                "interwiki_add" : "Interwiki add",
-                "edit_filter_add" : "Contents filter add",
-                "id_filter_add" : "ID filter add",
-                "email_filter_add" : "Email filter add",
-                "file_filter_add" : "File name filter add",
-                "edit_tool_add" : "Edit tool add",
-                "image_license_add" : "Image license add",
+                "interwiki_add" : "Add Interwiki",
+                "edit_filter_add" : "Add contents filter",
+                "id_filter_add" : "Add username filter",
+                "email_filter_add" : "Add email filter",
+                "file_filter_add" : "Add file name filter",
+                "edit_tool_add" : "Add edit tool",
+                "image_license_add" : "Add image license",
         "_comment_2.2_" : "Setting",
             "setting" : "Setting",
             "restart_required" : "Restart required",
@@ -224,15 +233,17 @@
                 "max_file_size" : "Max file size",
                 "backup_interval" : "Backup Cycles",
                 "wiki_skin" : "Wiki[s] default Skin",
-                "no_register" : "No sign-up",
+                "no_register" : "Disallow signing up",
                 "hide_ip" : "Hide IP address",
                 "wiki_host" : "Wiki host address",
                 "wiki_port" : "Wiki port number",
                 "wiki_secret_key" : "Wiki secret key",
                 "email_required" : "Email required",
-                "google_imap_required" : "Google IMAP setting required",
+                "smtp_setting_required" : "Email SMTP setting required",
                 "update_branch" : "Branch to import updates",
                 "slow_edit" : "Continuous edit limit",
+                "requires_approval" : "Requires approval for register",
+                "approval_question": "Registeration questions",
             "_comment_2.2.3_" : "Text",
                 "register_text" : "Terms of sign-up",
                 "non_login_alert" : "Non-login alert",
@@ -248,16 +259,19 @@
                 "edit_help" : "Editing textarea phrase",
             "_comment_2.2.4_" : "Google",
                 "recaptcha" : "reCAPTCHA",
-                "google_imap" : "Google IMAP",
-                "google_email" : "Google email",
-                "google_app_password" : "Google APP password",
+                "smtp_setting" : "Email SMTP setting",
+                "smtp_server" : "SMTP Server address",
+                "smtp_security": "SMTP Connection security",
+                "smtp_port" : "SMTP Server port",
+                "smtp_username" : "SMTP Username",
+                "smtp_password" : "SMTP Password",
         "_comment_2.3_" : "List",
             "open_discussion_list" : "Open discussion(s) list",
             "discussion_list" : "Discussion(s) list",
-            "admin_list" : "Admin(s) list",
+            "admin_list" : "Administrator(s) list",
             "member_list" : "Member(s) list",
             "authority_use_list" : "Authority use list",
-            "admin_group_list" : "Admin group(s) list",
+            "admin_group_list" : "Administrator group(s) list",
             "all_document_list" : "All document(s) list",
             "watchlist" : "Watchlist",
             "_comment_2.3.1_" : "ACL document list",
@@ -277,7 +291,7 @@
         "_comment_2.4_" : "Topic tool",
             "topic_tool" : "Discussion management tools",
             "topic_state" : "Discussion status",
-            "topic_delete" : "Discussion delete",
+            "topic_delete" : "Delete this thread",
         "_comment_2.5_" : "Period",
             "1_day" : "1 day",
             "5_day" : "5 days",
@@ -294,15 +308,26 @@
             "_comment_2.6_1_" : "Set",
                 "document_acl" : "Document ACL",
                 "discussion_acl" : "Discussion ACL",
-                "view_acl" : "Read ACL",
+                "view_acl" : "Reading ACL",
                 "user_document_acl" : "User document ACL",
                 "upload_acl" : "Upload ACL",
                 "edit_req_acl" : "Edit request ACL",
+        "_comment_2.7_" : "Application list",
+            "application_list": "Application list",
+            "application_time": "Application time",
+            "answer": "Answer",
+            "approve": "Approve",
+            "decline": "Decline",
+            "approve_or_decline": "Approve or reject",
+            "no_applications_now" : "There are no applications.",
+            "approval_requirement_disabled": "Approval requirement is disabled now. You can enable this feature on settings",
     "_comment_3_" : "Long",
+        "application_submitted": "Applicatied successfully for registration",
+        "waiting_for_approval": "Application for registration has been made successfully. Please wait for approval by administrators.",
         "ie_no_data_required" : "Operation cannot continue because all required data has not been collected.",
         "oauth_settings_not_found" : "The administrator has not provided any data about using this feature.",
         "oauth_disabled" : "The administrator has disabled this feature.",
-        "http_warring" : "Warning : If you are not on HTTPS connection, Your information can be leaked. We won't response to that.",
+        "http_warring" : "Warning: If you are not on HTTPS connection, Your information can be leaked. We won't response to that.",
         "user_head_warring" : "User <HEAD> will be deleted if you close the browser or when you sign in.",
         "no_login_warring" : "You are not logged in. The IP address will be logged when editing or discussing with non-login.",
         "user_reset_sign" : "Your account information has changed like this.",
@@ -311,6 +336,8 @@
         "markup_enabled" : "Markup enabled",
         "many_delete_help" : "Please write down the document[s] name one by one on the line.",
         "sqlite_only" : "SQLite only",
+        "approval_question_visible_only_when_approval_on" : "Approval questions are visible only when approval requirement is on",
+        "oauth_explain" : "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.",
         "_comment_3.1_" : "Error",
             "update_error" : "Auto update is not supported.",
             "inter_error" : "Internal error.",
@@ -319,24 +346,26 @@
             "no_exist_user_error" : "The account does not exist.",
             "no_admin_block_error" : "You cannot block or check administrators.",
             "skin_error" : "This skin is not support settings.",
-            "same_id_exist_error" : "There are users with the same ID.",
-            "long_id_error" : "ID must be shorter than 20 characters.",
-            "id_char_error" : "Only Korean letters, alphabet and space are allowed for ID.",
+            "same_id_exist_error" : "There are users with the same username.",
+            "long_id_error" : "Username must be shorter than 20 characters.",
+            "id_char_error" : "Only Korean letters, alphabets and spaces are allowed for Username.",
             "file_exist_error" : "The file does not exist.",
             "password_error" : "The password is different.",
             "recaptcha_error" : "Go through the reCAPTCHA.",
-            "file_extension_error" : "Only JPG, GIF, JPEG, PNG, WEBP is allowed.",
+            "file_extension_error" : "Only JPG, GIF, JPEG, PNG, WEBP files are allowed.",
             "edit_record_error" : "Edit reason can not be more than 500 characters.",
             "same_file_error" : "A file with the same name exists.",
-            "file_capacity_error" : "Maximum file capacity (MB) : ",
+            "file_capacity_error" : "Maximum file capacity (MB): ",
             "decument_exist_error" : "The document with that title already exists.",
             "password_diffrent_error" : "Reconfirm password and input password are different.",
             "edit_filter_error" : "Censored by edit filter.",
-            "file_name_error" : "Only alphabet, hangul, space, underscore, and minus signs are allowed for file names.",
+            "file_name_error" : "Only English alphabets, Korean alphabets, spaces, underscore, and hyphens are allowed for the file name.",
             "topic_long_error" : "The discussion[s] topic must not exceed 256 characters.",
             "email_error" : "No one has this email.",
             "regex_error" : "There is an error in the regular expression.",
             "decument_404_error" : "This document does not exist.",
             "fast_edit_error" : "You can edit another document after this period (Second(s)) : ",
-            "too_many_dec_error" : "This feature is not supported because there are too many documents."
+            "too_many_dec_error" : "This feature is not supported because there are too many documents.",
+            "application_not_found" : "Application not found",
+            "invalid_password_error" : "The Password or ID is invalid."
 }

+ 3 - 3
language/help_tool.py

@@ -1,11 +1,11 @@
 import re
 import json
 
-o_json = json.loads(open('en-US.json', encoding='utf-8').read())
+o_json = json.loads(open('en-US.json', encoding='utf8').read())
 
 print('n_name : ', end = '')
 n_name = input()
-n_json = json.loads(open(n_name + '.json', encoding='utf-8').read())
+n_json = json.loads(open(n_name + '.json', encoding='utf8').read())
 
 print()
 for i in list(n_json):
@@ -25,6 +25,6 @@ for i in list(o_json):
 
 n_data = json.dumps(n_json, indent = 4, ensure_ascii = False)
 
-f = open(n_name + '.json', "w", encoding='utf-8')
+f = open(n_name + '.json', "w", encoding='utf8')
 f.write(n_data)
 f.close()

+ 52 - 24
language/ko-KR.json

@@ -1,4 +1,5 @@
 {
+    "delete_admin_group": "관리자 그룹 삭제",
     "document_name": "문서명",
     "non_login_alert": "비로그인 알림",
     "hide": "숨김",
@@ -8,7 +9,7 @@
     "compare_target": "비교 대상 이름",
     "email_title": "이메일 제목",
     "acl_required": "ACL 필요",
-    "blocked": "차단",
+    "blocked": "차단",
     "authorization_authority": "권한 부여 권한",
     "open_discussion": "열린 토론",
     "move_history": "이동 기록",
@@ -18,7 +19,10 @@
     "view_acl": "읽기 ACL",
     "notice": "알림",
     "login": "로그인",
-    "google_imap": "Google IMAP",
+    "smtp_setting": "이메일 SMTP 설정",
+    "smtp_server" : "SMTP 서버 주소",
+    "smtp_security": "SMTP 보안 프로토콜",
+    "smtp_port" : "SMTP 서버 포트",
     "close": "닫기",
     "closed": "닫힘",
     "start": "시작",
@@ -42,7 +46,7 @@
     "state": "상태",
     "authorize": "권한 부여",
     "check_user": "사용자 검사",
-    "email_acl": "이메일을 가진 유저만",
+    "email_acl": "이메일을 가진 사용자만",
     "email_error": "해당 이메일을 가진 사용자가 존재하지 않습니다.",
     "version": "버전",
     "open": "열기",
@@ -71,7 +75,7 @@
     "wiki_name": "위키 이름",
     "acl_document_list": "ACL 문서 목록",
     "connection": "연결",
-    "oauth_disabled": "관리자가 이 기능을 비활성화 시켰습니다.",
+    "oauth_disabled": "관리자가 이 기능을 비활성화시켰습니다.",
     "random": "무작위",
     "filter": "필터",
     "band_blocked": "대역 차단됨",
@@ -106,7 +110,7 @@
     "range": "범위",
     "edit_filter_rule": "편집 필터 규칙",
     "oauth_connection": "Oauth 연결",
-    "hide_ip": "IP 숨기기",
+    "hide_ip": "IP 주소 숨기기",
     "topic_tool": "토론 관리 도구",
     "user_document": "사용자 문서",
     "id": "아이디",
@@ -130,7 +134,7 @@
     "file_filter_add": "파일명 필터 추가",
     "wiki_restart": "위키 엔진 재시작",
     "oauth_settings_not_found": "관리자가 해당 기능을 수행하기 위해 필요한 데이터를 제공하지 않았습니다.",
-    "discussion_raw": "토론 원본",
+    "discussion_raw": "토론 댓글 원본",
     "main_setting": "메인 설정",
     "password": "비밀번호",
     "update_error": "자동 업데이트가 지원되지 않습니다.",
@@ -142,7 +146,7 @@
     "pinned": "고정",
     "edit_filter_add": "편집 필터 추가",
     "ban_authority": "차단 권한",
-    "file_extension_error": "오직 JPG, GIF, JPEG, PNG, WEBP 만 업로드 할 수 있습니다.",
+    "file_extension_error": "오직 JPG, GIF, JPEG, PNG, WEBP 형식의 파일만 업로드할 수 있습니다.",
     "host": "호스트",
     "email_text": "이메일 내용",
     "recent": "최근",
@@ -160,7 +164,7 @@
     "wiki_skin": "위키 스킨",
     "admin_group": "관리자 그룹",
     "all": "전체",
-    "skin_error": "해당 스킨은 스킨 설정을 지원하지 않습니다.",
+    "skin_error": "사용 중인 스킨은 스킨 설정 기능을 지원하지 않습니다.",
     "member": "가입자",
     "backlink": "역링크",
     "no_admin_block_error": "관리자는 검사, 차단을 할 수 없습니다.",
@@ -181,17 +185,17 @@
     "text_setting": "문구 설정",
     "document_acl_authority": "문서 ACL 관리 권한",
     "wiki_logo": "위키 로고",
-    "google_imap_required": "Google IMAP 설정 필요",
+    "smtp_setting_required": "이메일 SMTP 설정 필요",
     "adsense_setting": "애드센스 설정",
-    "google_email": "Google 이메일",
+    "smtp_username": "SMTP 아이디",
     "previous": "이전",
-    "name_or_ip_or_regex": "ID or IP or 정규식",
+    "name_or_ip_or_regex": "사용자 이름 혹은 IP 주소 혹은 정규표현식",
     "editor": "편집자",
     "wiki_secret_key": "위키 비밀 키",
     "band_ban": "대역 차단",
-    "http_warring": "경고 : HTTPS 연결을 사용하지 않는다면 개인정보가 유출될 수 있습니다. 이 사항에 의해 입는 피해는 사용자에게 책임이 있음을 알려드립니다.",
+    "http_warring": "경고: HTTPS 연결을 사용하지 않는다면 개인정보가 유출될 수 있습니다. 이 사항에 의해 입는 피해는 사용자에게 책임이 있음을 알려드립니다.",
     "update_warring": "최신 버전보다 0.2 버전 이상 낮은 경우 수동 업데이트를 권장합니다. 윈도우의 경우 route 폴더의 내용이 사라집니다.",
-    "discussion_name": "토론",
+    "discussion_name": "토론 제목",
     "discussion": "토론",
     "main": "메인",
     "server": "서버",
@@ -201,7 +205,7 @@
     "logout": "로그아웃",
     "bottom_text": "하단 내용",
     "30_day": "30일",
-    "topic_long_error": "토론 이름은 256자를 넘을 수 없습니다.",
+    "topic_long_error": "토론 제목은 256자를 넘을 수 없습니다.",
     "error_401": "ACL 읽기 제한 문서 문구",
     "history": "역사",
     "admin_group_list": "관리자 그룹 목록",
@@ -243,9 +247,11 @@
     "user_head": "사용자 <HEAD>",
     "agreement": "동의",
     "stop": "중지",
+    "application_submitted": "회원가입 신청 완료",
+    "waiting_for_approval": "회원가입 신청이 정상적으로 접수됐습니다. 관리자의 승인을 기다려주세요.",
     "ie_no_data_required": "이 기능을 수행하기 위해 필요한 데이터가 제공되지 않았습니다.",
     "port": "포트",
-    "reload": "새로고침",
+    "reload": "갱신",
     "indexing": "DB 인덱싱",
     "topic_state": "토론 상태",
     "watchlist": "주시 목록",
@@ -253,19 +259,19 @@
     "user": "사용자",
     "skin_info": "스킨 정보",
     "new_connection": "연결...",
-    "discussion_record": "토론 기록",
+    "discussion_record": "토론 참여 기록",
     "move": "이동",
     "recent_change": "최근 편집",
     "destruction": "취소",
     "count": "기여 횟수",
     "main_head": "메인 <HEAD>",
     "recent_ban": "최근 차단",
-    "google_app_password": "Google 앱 비밀번호",
+    "smtp_password": "SMTP Password",
     "id_filter_list": "ID 필터 목록",
     "other": "기타",
     "edit": "편집",
     "open_discussion_list": "열린 토론 목록",
-    "user_head_warring": "비로그인시 브라우저를 닫거나 로그인시 사용자 <HEAD>는 삭제됩니다.",
+    "user_head_warring": "비로그인시 브라우저를 닫거나 로그인시 사용자가 지정한 <HEAD>는 삭제됩니다.",
     "email_required": "이메일 필요",
     "1_day": "1일",
     "regex_error": "정규표현식에 오류가 있습니다.",
@@ -274,7 +280,7 @@
     "hide_release": "숨김 해제",
     "360_day": "360일",
     "inter_error": "내부 오류.",
-    "50_edit_acl": "기여 횟수 총합 50회 이상 가입자만",
+    "50_edit_acl": "기여 횟수가 50회 이상인 가입자만",
     "tool": "도구",
     "adsense_enable": "애드센스 사용",
     "list": "목록",
@@ -299,9 +305,9 @@
     "old_page": "오래된 문서",
     "skin_set": "스킨 설정",
     "edit_help": "편집 창 문구",
-    "defalut_edit_help": "이곳에 내용을 입력해 주세요.",
-    "many_delete": "대량 삭제",
-    "many_delete_help": "한 줄에 한 개씩 적어주세요.",
+    "defalut_edit_help": "이곳에 내용을 입력해주세요.",
+    "many_delete": "문서 대량 삭제",
+    "many_delete_help": "한 줄에 문서명을 한 개씩 적어주세요.",
     "content": "내용",
     "upload_acl": "파일 업로드 ACL",
     "topic_delete": "토론 삭제",
@@ -310,10 +316,32 @@
     "sqlite_only": "SQLite만",
     "off": "끄기",
     "slow_edit": "편집 속도 제한 시간",
+    "requires_approval" : "가입시 승인 필요",
+    "approval_question": "회원가입 질문",
     "public_key": "공개 키",
-    "fast_edit_error": "편집 속도가 너무 빠릅니다. 제한 (초) : ",
+    "fast_edit_error": "편집 속도가 너무 빠릅니다. 제한 (초): ",
     "main_acl_setting": "기본 ACL 설정",
     "edit_req_acl": "편집 요청 ACL",
+    "application_list": "가입신청 목록",
+    "application_time": "가입신청 일시",
+    "answer": "답변",
+    "approve": "승인",
+    "decline": "거절",
+    "approve_or_decline": "승인 및 거절",
     "history_add" : "역사 추가",
-    "too_many_dec_error" : "문서 수가 너무 많아서 지원하지 않는 기능 입니다."
+    "too_many_dec_error" : "문서 수가 너무 많아서 지원하지 않는 기능입니다.",
+    "approval_question_visible_only_when_approval_on" : "회원가입 질문은 가입시 승인필요 설정이 활성화됐을때만 보여집니다.",
+    "no_applications_now" : "회원가입 신청이 없습니다.",
+    "application_not_found" : "존재하지 않는 회원가입 신청입니다.",
+    "approval_requirement_disabled": "현재 가입시 승인필요 설정이 비활성화되어있습니다. 필요시 설정에서 활성화할 수 있습니다.",
+    "all_register_num" : "모든 가입 신청자의 수",
+    "replace_move" : "문서 바꾸기",
+    "merge_move" : "문서 병합",
+    "oauth_explain" : "OAuth 로그인 기능을 사용하려면 'publish_url' 값을 HTTPS 프로토콜을 포함한 도메인 주소로 설정하고, 실제로 HTTPS 연결을 지원해야 합니다.",
+    "add_admin_group" : "관리자 그룹 추가",
+    "add_watchlist" : "주시 문서 추가",
+    "blocked_user" : "차단된 사용자",
+    "blocked_admin" : "차단한 관리자",
+    "invalid_password_error" : "비밀번호 또는 아이디가 없습니다.",
+    "accept_edit_request": "편집 요청 승인"
 }

+ 1 - 1
readme-en.md

@@ -79,4 +79,4 @@ openNAMU is protected by [BSD 3-Clause License](./LICNESE). Please refer to the
 
 # Etc.
  * Owner rights are granted to the first registor.
- * [Test Server](http://namu.ml)
+ * [Test Server](http://2du.pythonanywhere.com)

+ 1 - 1
readme.md

@@ -53,4 +53,4 @@
 
 ## 기타
  * 첫 가입자에게 소유자 권한이 부여됩니다.
- * [테스트 서버](http://namu.ml)
+ * [테스트 서버](http://2du.pythonanywhere.com)

+ 1 - 0
requirements.txt

@@ -4,4 +4,5 @@ flask
 flask-Reggie
 flask-compress
 pymysql
+diff-match-patch
 pysha3; python_version < "3.6"

+ 9 - 0
route/api_image_view.py

@@ -0,0 +1,9 @@
+from .tool.func import *
+
+def api_image_view_2(conn, name, app_var):
+    curs = conn.cursor()
+
+    if os.path.exists(os.path.join(app_var['path_data_image'], name)):
+        return flask.jsonify({ "exist" : "1" })
+    else:
+        return flask.jsonify({})

+ 30 - 6
route/api_skin_info.py

@@ -11,7 +11,7 @@ def api_skin_info_2(conn, name):
     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())
+            json_data = json.loads(open(json_address, encoding='utf8').read())
         except:
             json_data = None
 
@@ -21,10 +21,16 @@ def api_skin_info_2(conn, name):
             return flask.jsonify({}), 404
     else:
         a_data = {}
+        d_link_data = {
+            "ACME" : "https://raw.githubusercontent.com/openNAMU/openNAMU-Skin-ACME/master/info.json",
+            "Liberty" : "https://raw.githubusercontent.com/openNAMU/openNAMU-Skin-Liberty/master/info.json",
+            "Before Namu" : "https://raw.githubusercontent.com/openNAMU/openNAMU-Skin-Before_Namu/master/info.json"
+        }
+
         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())
+                json_data = json.loads(open(json_address, encoding='utf8').read())
             except:
                 json_data = None
 
@@ -32,9 +38,27 @@ def api_skin_info_2(conn, name):
                 if i == skin_check(1):
                     json_data = {**json_data, **{ "main" : "true" }}
 
+                if "info_link" in json_data:
+                    info_link = json_data["info_link"]
+                    get_num = 1
+                elif json_data["name"] in d_link_data:
+                    info_link = d_link_data[json_data["name"]]
+                    get_num = 1
+                else:
+                    get_num = 0
+
+                if get_num == 1:
+                    get_data = urllib.request.urlopen(info_link)
+                    if get_data and get_data.getcode() == 200:
+                        try:
+                            get_data = json.loads(get_data.read().decode())
+                            if "skin_ver" in get_data:
+                                json_data = {**json_data, **{ "lastest_version" : {
+                                    "skin_ver" : json_data["skin_ver"]
+                                }}}
+                        except:
+                            pass
+
                 a_data = {**a_data, **{ i : json_data }}
 
-        if a_data == {}:
-            return flask.jsonify({})
-        else:
-            return flask.jsonify(a_data)
+        return flask.jsonify(a_data)

+ 9 - 2
route/api_topic_sub.py

@@ -73,6 +73,10 @@ def api_topic_sub_2(conn, topic_num):
                 if t_data_f == '':
                     t_data_f = '[br]'
 
+                t_data_f = render_set(data = t_data_f, num = 2, include = 'topic_' + i[0])
+                t_plus_data = t_data_f[1]
+                t_data_f = t_data_f[0]
+
                 all_data = '' + \
                     '<table id="toron">' + \
                         '<tbody>' + \
@@ -82,7 +86,9 @@ def api_topic_sub_2(conn, topic_num):
                                 '</td>' + \
                             '</tr>' + \
                             '<tr>' + \
-                                '<td id="' + b_color + '">' + render_set(data = t_data_f, include = 'topic_' + i[0]) + '</td>' + \
+                                '<td id="' + b_color + '">' + \
+                                    '<div id="topic_scroll">' + t_data_f + '</div>' + \
+                                '</td>' + \
                             '</tr>' + \
                         '</tbody>' + \
                     '</table>' + \
@@ -90,7 +96,8 @@ def api_topic_sub_2(conn, topic_num):
                 ''
 
                 json_data[i[0]] = {
-                    "data" : all_data
+                    "data" : all_data,
+                    "plus_data" : t_plus_data
                 }
             else:
                 if i[4] != 'O' or (i[4] == 'O' and admin == 1):

+ 5 - 1
route/api_user_info.py

@@ -33,7 +33,11 @@ def api_user_info_2(conn, name):
         data = curs.fetchall()
         if data:
             if data[0][0] != 'user':
-                plus_t += [data[0][0]]
+                curs.execute(db_change("select name from alist where name = ?"), [data[0][0]])
+                if curs.fetchall():
+                    plus_t += [data[0][0]]
+                else:
+                    plus_t += [load_lang('member')]
             else:
                 plus_t += [load_lang('member')]
         else:

+ 8 - 1
route/api_w.py

@@ -24,7 +24,14 @@ def api_w_2(conn, name):
                         category_re = re.compile('\[\[(?:(?:category|분류):(?:(?!\[\[|\]\]).)+)\]\]', re.I)
 
                         json_data = include_re.sub('', data[0][0])
-                        json_data = category_re.sub('', json_data, )
+                        json_data = category_re.sub('', json_data)
+
+                        get_all_change = re.findall('(@(?:[^@]*)@),([^,]*),', flask.request.args.get('change', ''))
+                        for i in get_all_change:
+                            json_data = json_data.replace(
+                                i[0].replace('<amp>', '&'), 
+                                i[1].replace('<amp>', '&').replace('<comma>', ',')
+                            )
 
                         g_data = render_set(title = name, data = json_data, num = 2, include = flask.request.args.get('include', 'include_1'))
                     else:

+ 10 - 0
route/application_submitted.py

@@ -0,0 +1,10 @@
+from .tool.func import *
+
+def application_submitted_2(conn):
+    curs = conn.cursor()
+
+    return easy_minify(flask.render_template(skin_check(),
+        imp = [load_lang('application_submitted'), wiki_set(), custom(), other2([0, 0])],
+        data =  '''<p>''' + load_lang('waiting_for_approval') + '''</p>''',
+        menu = [['user', load_lang('return')]]
+    ))

+ 108 - 0
route/applications.py

@@ -0,0 +1,108 @@
+from .tool.func import *
+
+def applications_2(conn):
+    curs = conn.cursor()
+
+    div = ''
+    admin = admin_check()
+
+    if admin != 1:
+        return re_error('/ban')
+
+    curs.execute(db_change('select data from other where name = "requires_approval"'))
+    requires_approval = curs.fetchall()
+    if requires_approval and requires_approval[0][0] != 'on':
+        div += '<p>' + load_lang('approval_requirement_disabled') + '</p>'
+
+    if flask.request.method == 'GET':
+        curs.execute(db_change('select id, date, question, answer, token, email from user_application'))
+        db_data = curs.fetchall()
+        if db_data:
+            div += '<p>' + load_lang('all_register_num') + ' : ' + str(len(db_data)) + '</p><br>'
+
+            for application in db_data:
+                question = application[2]
+                answer = application[3]
+                email = application[5]
+                if not question:
+                    question = ''
+                if not answer:
+                    answer = ''
+                if not email:
+                    email = ''
+                div += '''
+                    <form method=\"post\">
+                        <table>
+                            <tbody>
+                                <tr>
+                                    <td>''' + load_lang('id') + '''</td><td>''' + application[0] + '''</td>
+                                </tr>
+                                <tr>
+                                    <td>''' + load_lang('application_time') + '''</td><td>''' + application[1] + '''</td>
+                                </tr>
+                                <tr>
+                                    <td>''' + load_lang('approval_question') + '''</td><td>''' + question + '''</td>
+                                </tr>
+                                <tr>
+                                    <td>''' + load_lang('answer') + '''</td><td>''' + html.escape(answer) + '''</td>
+                                </tr>
+                                <tr>
+                                    <td>''' + load_lang('email') + '''</td><td>''' + html.escape(email) + '''</td>
+                                </tr>
+                                <tr>
+                                    <td colspan=\"2\" style=\"text-align: center;\">
+                                        <button type=\"submit\" name=\"approve\" value=\"''' + application[4] + '''\">''' + load_lang('approve') + '''</button>
+                                        <button type=\"submit\" name=\"decline\" value=\"''' + application[4] + '''\">''' + load_lang('decline') + '''</button>
+                                    </td>
+                                </tr>
+                            </tbody>
+                        </table>
+                    </form>
+                    <br>
+                '''
+        else:
+            div += load_lang('no_applications_now')
+    else:
+        if flask.request.form.get('approve', '') != '':
+            curs.execute(db_change('select id, pw, date, encode, question, answer, ip, ua, email from user_application where token = ?'), [flask.request.form.get('approve', '')])
+            application = curs.fetchall()
+            if not application:
+                return re_error('/error/26')
+            
+            application = application[0]
+
+            curs.execute(db_change("select id from user where id = ?"), [application[0]])
+            if curs.fetchall():
+                return re_error('/error/6')
+            
+            curs.execute(db_change("insert into user (id, pw, acl, date, encode) values (?, ?, 'user', ?, ?)"), [
+                application[0], 
+                application[1], 
+                application[2], 
+                application[3]
+            ])
+            curs.execute(db_change("insert into user_set (name, id, data) values ('approval_question', ?, ?)"), [application[0], application[4]])
+            curs.execute(db_change("insert into user_set (name, id, data) values ('approval_question_answer', ?, ?)"), [application[0], application[5]])
+            curs.execute(db_change("insert into ua_d (name, ip, ua, today, sub) values (?, ?, ?, ?, '')"), [
+                application[0], 
+                application[6], 
+                application[7], 
+                application[2]
+            ])
+            if application[8] and application[8] != '':
+                curs.execute(db_change("insert into user_set (name, id, data) values ('email', ?, ?)"), [application[0], application[8]])
+            curs.execute(db_change('delete from user_application where token = ?'), [flask.request.form.get('approve', '')])
+ 
+
+            conn.commit()
+        elif flask.request.form.get('decline', '') != '':
+            curs.execute(db_change('delete from user_application where token = ?'), [flask.request.form.get('decline', '')])
+            conn.commit()
+
+        return redirect('/applications')
+
+    return easy_minify(flask.render_template(skin_check(),
+        imp = [load_lang('application_list'), wiki_set(), custom(), other2([0, 0])],
+        data = div,
+        menu = [['other', load_lang('return')]]
+    ))

+ 11 - 4
route/edit.py

@@ -36,7 +36,10 @@ def edit_2(conn, name):
             leng = leng_check(len(flask.request.form.get('otent', '')), len(content))
             
             if section:
-                content = old[0][0].replace(flask.request.form.get('otent', ''), content)
+                content = old[0][0].replace('\r\n', '\n').replace(
+                    flask.request.form.get('otent', '').replace('\r\n', '\n'), 
+                    content.replace('\r\n', '\n')
+                )
         else:
             leng = '+' + str(len(content))
 
@@ -80,7 +83,11 @@ def edit_2(conn, name):
     else:            
         if old:
             if section:
-                data = re.sub('\n(?P<in>={1,6})', '<br>\g<in>', html.escape('\n' + re.sub('\r\n', '\n', old[0][0]) + '\n'))
+                data = re.sub(
+                    '\n(?P<in>={1,6})', 
+                    '<br>\g<in>', 
+                    html.escape('\n' + old[0][0].replace('\r\n', '\n') + '\n')
+                )
                 i = 0
 
                 while 1:
@@ -97,7 +104,7 @@ def edit_2(conn, name):
                     else:
                         break
             else:
-                data = old[0][0]
+                data = old[0][0].replace('\r\n', '\n')
         else:
             data = ''
             
@@ -105,7 +112,7 @@ def edit_2(conn, name):
         get_name = ''
 
         if not section:
-            get_name =  '''
+            get_name = '''
                 <a href="/manager/15?plus=''' + url_pas(name) + '">(' + load_lang('load') + ')</a> <a href="/edit_filter">(' + load_lang('edit_filter_rule') + ''')</a>
                 <hr class=\"main_hr\">
             '''

+ 6 - 4
route/edit_delete.py

@@ -43,10 +43,12 @@ def edit_delete_2(conn, name, app_var):
         file_check = re.search('^file:(.+)\.(.+)$', name)
         if file_check:
             file_check = file_check.groups()
-            os.remove(os.path.join(
-                app_var['path_data_image'],
-                sha224_replace(file_check[0], 'utf-8') + '.' + file_check[1]
-            ))
+            file_directory = os.path.join(
+                app_var['path_data_image'], 
+                sha224_replace(file_check[0]) + '.' + file_check[1]
+            )
+            if os.path.exists(file_directory):
+                os.remove(file_directory)
 
         curs.execute(db_change('select data from other where name = "count_all_title"'))
         curs.execute(db_change("update other set data = ? where name = 'count_all_title'"), [str(int(curs.fetchall()[0][0]) - 1)])

+ 5 - 3
route/edit_many_delete.py

@@ -37,10 +37,12 @@ def edit_many_delete_2(conn, app_var):
             file_check = re.search('^file:(.+)\.(.+)$', name)
             if file_check:
                 file_check = file_check.groups()
-                os.remove(os.path.join(
-                    app_var['path_data_image'],
+                file_directory = os.path.join(
+                    app_var['path_data_image'], 
                     sha224_replace(file_check[0]) + '.' + file_check[1]
-                ))
+                )
+                if os.path.exists(file_directory):
+                    os.remove(file_directory)
 
             curs.execute(db_change('select data from other where name = "count_all_title"'))
             curs.execute(db_change("update other set data = ? where name = 'count_all_title'"), [str(int(curs.fetchall()[0][0]) - 1)])

+ 85 - 29
route/edit_move.py

@@ -15,20 +15,22 @@ def edit_move_2(conn, name):
         if slow_edit_check() == 1:
             return re_error('/error/24')
 
-        curs.execute(db_change("select title from history where title = ?"), [flask.request.form.get('title', None)])
+        move_title = flask.request.form.get('title', 'test')
+
+        curs.execute(db_change("select title from history where title = ?"), [move_title])
         if curs.fetchall():
-            if admin_check(None, 'merge documents') == 1:
-                curs.execute(db_change("select data from data where title = ?"), [flask.request.form.get('title', None)])
+            if flask.request.form.get('move_option', 'normal') == 'merge' and admin_check(None, 'merge documents') == 1:
+                curs.execute(db_change("select data from data where title = ?"), [move_title])
                 data = curs.fetchall()
                 if data:
-                    curs.execute(db_change("delete from data where title = ?"), [flask.request.form.get('title', None)])
-                    curs.execute(db_change("delete from back where link = ?"), [flask.request.form.get('title', None)])
+                    curs.execute(db_change("delete from data where title = ?"), [move_title])
+                    curs.execute(db_change("delete from back where link = ?"), [move_title])
 
                 curs.execute(db_change("select data from data where title = ?"), [name])
                 data = curs.fetchall()
                 if data:
-                    curs.execute(db_change("update data set title = ? where title = ?"), [flask.request.form.get('title', None), name])
-                    curs.execute(db_change("update back set link = ? where link = ?"), [flask.request.form.get('title', None), name])
+                    curs.execute(db_change("update data set title = ? where title = ?"), [move_title, name])
+                    curs.execute(db_change("update back set link = ? where link = ?"), [move_title, name])
 
                     data_in = data[0][0]
                 else:
@@ -41,13 +43,13 @@ def edit_move_2(conn, name):
                     ip_check(),
                     flask.request.form.get('send', ''),
                     '0',
-                    'marge <a>' + name + '</a> - <a>' + flask.request.form.get('title', 'test') + '</a> move'
+                    'marge <a>' + name + '</a> - <a>' + move_title + '</a> move'
                 )
 
                 curs.execute(db_change("update back set type = 'no' where title = ? and not type = 'cat' and not type = 'no'"), [name])
-                curs.execute(db_change("delete from back where title = ? and not type = 'cat' and type = 'no'"), [flask.request.form.get('title', None)])
+                curs.execute(db_change("delete from back where title = ? and not type = 'cat' and type = 'no'"), [move_title])
 
-                curs.execute(db_change("select id from history where title = ? order by id + 0 desc limit 1"), [flask.request.form.get('title', None)])
+                curs.execute(db_change("select id from history where title = ? order by id + 0 desc limit 1"), [move_title])
                 data = curs.fetchall()
 
                 num = data[0][0]
@@ -55,19 +57,67 @@ def edit_move_2(conn, name):
                 curs.execute(db_change("select id from history where title = ? order by id + 0 asc"), [name])
                 data = curs.fetchall()
                 for move in data:
-                    curs.execute(db_change("update history set title = ?, id = ? where title = ? and id = ?"), [flask.request.form.get('title', None), str(int(num) + int(move[0])), name, move[0]])
+                    curs.execute(db_change("update history set title = ?, id = ? where title = ? and id = ?"), [
+                        move_title, 
+                        str(int(num) + int(move[0])), 
+                        name, 
+                        move[0]
+                    ])
 
                 conn.commit()
 
-                return redirect('/w/' + url_pas(flask.request.form.get('title', None)))
+                return redirect('/w/' + url_pas(move_title))
+            elif flask.request.form.get('move_option', 'normal') == 'reverse':
+                var_name = ''
+                i = 0
+                while 1:
+                    curs.execute(db_change("select title from history where title = ?"), ['test ' + str(i)])
+                    if not curs.fetchall():
+                        curs.execute(db_change("select data from data where title = ?"), [name])
+                        data = curs.fetchall()
+                        if data:
+                            curs.execute(db_change("update data set title = ? where title = ?"), ['test ' + str(i), name])
+                            curs.execute(db_change("update back set link = ? where link = ?"), ['test ' + str(i), name])
+
+                        curs.execute(db_change("update history set title = ? where title = ?"), ['test ' + str(i), name])
+
+                        break
+                    else:
+                        i += 1
+
+                for title_name in [[move_title, name], ['test ' + str(i), move_title]]:
+                    curs.execute(db_change("select data from data where title = ?"), [title_name[0]])
+                    data = curs.fetchall()
+                    if data:
+                        curs.execute(db_change("update data set title = ? where title = ?"), [title_name[1], title_name[0]])
+                        curs.execute(db_change("update back set link = ? where link = ?"), [title_name[1], title_name[0]])
+
+                        data_in = data[0][0]
+                    else:
+                        data_in = ''
+
+                    history_plus(
+                        title_name[0],
+                        data_in,
+                        get_time(),
+                        ip_check(),
+                        flask.request.form.get('send', ''),
+                        '0',
+                        '<a>' + (title_name[0] if title_name[0] != 'test ' + str(i) else name) + '</a> - <a>' + title_name[1] + '</a> move'
+                    )
+
+                    curs.execute(db_change("update history set title = ? where title = ?"), [title_name[1], title_name[0]])
+                    conn.commit()
+
+                return redirect('/w/' + url_pas(move_title))
             else:
                 return re_error('/error/19')
         else:
             curs.execute(db_change("select data from data where title = ?"), [name])
             data = curs.fetchall()
             if data:
-                curs.execute(db_change("update data set title = ? where title = ?"), [flask.request.form.get('title', None), name])
-                curs.execute(db_change("update back set link = ? where link = ?"), [flask.request.form.get('title', None), name])
+                curs.execute(db_change("update data set title = ? where title = ?"), [move_title, name])
+                curs.execute(db_change("update back set link = ? where link = ?"), [move_title, name])
 
                 data_in = data[0][0]
             else:
@@ -80,29 +130,35 @@ def edit_move_2(conn, name):
                 ip_check(),
                 flask.request.form.get('send', ''),
                 '0',
-                '<a>' + name + '</a> - <a>' + flask.request.form.get('title', 'test') + '</a> move'
+                '<a>' + name + '</a> - <a>' + move_title + '</a> move'
             )
 
             curs.execute(db_change("update back set type = 'no' where title = ? and not type = 'cat' and not type = 'no'"), [name])
-            curs.execute(db_change("delete from back where title = ? and not type = 'cat' and type = 'no'"), [flask.request.form.get('title', None)])
+            curs.execute(db_change("delete from back where title = ? and not type = 'cat' and type = 'no'"), [move_title])
 
-            curs.execute(db_change("update history set title = ? where title = ?"), [flask.request.form.get('title', None), name])
+            curs.execute(db_change("update history set title = ? where title = ?"), [move_title, name])
             conn.commit()
 
-            return redirect('/w/' + url_pas(flask.request.form.get('title', None)))
+            return redirect('/w/' + url_pas(move_title))
     else:
         return easy_minify(flask.render_template(skin_check(),
             imp = [name, wiki_set(), custom(), other2([' (' + load_lang('move') + ')', 0])],
-            data =  '''
-                    <form method="post">
-                        ''' + ip_warring() + '''
-                        <input placeholder="''' + load_lang('document_name') + '" value="' + name + '''" name="title" type="text">
-                        <hr class=\"main_hr\">
-                        <input placeholder="''' + load_lang('why') + '''" name="send" type="text">
-                        <hr class=\"main_hr\">
-                        ''' + captcha_get() + '''
-                        <button type="submit">''' + load_lang('move') + '''</button>
-                    </form>
-                    ''',
+            data = '''
+                <form method="post">
+                    ''' + ip_warring() + '''
+                    <input placeholder="''' + load_lang('document_name') + '" value="' + name + '''" name="title" type="text">
+                    <hr class=\"main_hr\">
+                    <input placeholder="''' + load_lang('why') + '''" name="send" type="text">
+                    <hr class=\"main_hr\">
+                    <select name="move_option">
+                        <option value="normal"> ''' + load_lang('normal') + '''</option>
+                        <option value="reverse"> ''' + load_lang('replace_move') + '''</option>
+                        ''' + ('<option value="merge"> ' + load_lang('merge_move') + '</option>' if admin_check() == 1 else '') + '''
+                    </select>
+                    <hr class=\"main_hr\">
+                    ''' + captcha_get() + '''
+                    <button type="submit">''' + load_lang('move') + '''</button>
+                </form>
+            ''',
             menu = [['w/' + url_pas(name), load_lang('return')]]
         ))

+ 6 - 3
route/edit_req.py

@@ -57,7 +57,10 @@ def edit_req_2(conn, name):
             leng = leng_check(len(flask.request.form.get('otent', '')), len(content))
 
             if section:
-                content = old[0][0].replace(flask.request.form.get('otent', ''), content)
+                content = old[0][0].replace(
+                    flask.request.form.get('otent', '').replace('\r\n', '\n'), 
+                    content.replace('\r\n', '\n')
+                )
         else:
             leng = '+' + str(len(content))
 
@@ -121,7 +124,7 @@ def edit_req_2(conn, name):
         data_old = data
         get_name = ''
 
-        save_button = load_lang('edit_req') if not get_ver else load_lang('edit_req_check')
+        save_button = load_lang('edit_req') if not get_ver else load_lang('accept_edit_request')
         menu_plus = [[]]
         sub = load_lang('edit_req')
         disable = '' if not get_ver else 'disabled'
@@ -160,4 +163,4 @@ def edit_req_2(conn, name):
                 <div id="see_preview"></div>
             ''',
             menu = [['w/' + url_pas(name), load_lang('return')]] + menu_plus
-        ))
+        ))

+ 8 - 12
route/func_upload.py

@@ -48,20 +48,16 @@ def func_upload_2(conn):
         ip = ip_check()
 
         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)
+            lice = flask.request.form.get('f_lice', None) + '[br][br]'
+            if ip_or_user(ip) != 0:
+                lice += ip
             else:
-                if ip_or_user(ip) != 0:
-                    lice = ip
-                else:
-                    lice = '[[user:' + ip + ']]'
+                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 += '[br][br]'  + 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)):
@@ -109,7 +105,7 @@ def func_upload_2(conn):
 
         return easy_minify(flask.render_template(skin_check(),
             imp = [load_lang('upload'), wiki_set(), custom(), other2([0, 0])],
-            data =  '''
+            data = '''
                 <a href="/file_filter">(''' + load_lang('file_filter_list') + ''')</a>
                 <hr class=\"main_hr\">
                 ''' + load_lang('max_file_size') + ''' : ''' + wiki_set(3) + '''MB
@@ -117,13 +113,13 @@ def func_upload_2(conn):
                 <form method="post" enctype="multipart/form-data" accept-charset="utf8">
                     <input type="file" name="f_data">
                     <hr class=\"main_hr\">
-                    <input placeholder="''' + load_lang('file_name') + '''" name="f_name" type="text" value="''' + flask.request.args.get('name', '') + '''">
+                    <input placeholder="''' + load_lang('file_name') + '''" name="f_name" value="''' + flask.request.args.get('name', '') + '''">
                     <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">
+                    <textarea rows="10" placeholder="''' + load_lang('other') + '''" name="f_lice"></textarea>
                     <hr class=\"main_hr\">
                     ''' + captcha_get() + '''
                     <button id="save" type="submit">''' + load_lang('save') + '''</button>

+ 23 - 0
route/give_delete_admin_group.py

@@ -0,0 +1,23 @@
+from .tool.func import *
+
+def delete_admin_group_2(conn, name):
+    curs = conn.cursor()
+
+    if admin_check() != 1:
+        return re_error('/error/3')
+    
+    if flask.request.method == 'POST':
+        admin_check(None, 'alist del ' + name)
+        curs.execute(db_change("delete from alist where name = ?"), [name])
+
+        return redirect('/give_log')
+    
+    return easy_minify(flask.render_template(skin_check(),
+        imp = [load_lang("delete_admin_group"), wiki_set(), custom(), other2(['(' + name + ')', 0])],
+        data = '''
+            <form method=post>
+                <button type=submit>''' + load_lang('start') + '''</button>
+            </form>
+        ''',
+        menu = [['give_log', load_lang('return')]]
+    ))  

+ 34 - 11
route/give_user_check.py

@@ -18,6 +18,29 @@ def give_user_check_2(conn, name):
     else:
         sql_num = 0
 
+    if ip_or_user(name) == 0:
+        curs.execute(db_change("select data from user_set where name = \"approval_question\" and id = ?"), [name])
+        approval_question = curs.fetchall()
+        if approval_question and approval_question[0][0]:
+            curs.execute(db_change("select data from user_set where name = \"approval_question_answer\" and id = ?"), [name])
+            approval_question_answer = curs.fetchall()
+            if approval_question_answer and approval_question_answer[0]:
+                div = '''
+                    <table id="main_table_set">
+                        <tbody>
+                            <tr>
+                                <td>Q</td>
+                                <td>''' + approval_question[0][0] + '''</td>
+                                <td>A</td>
+                                <td>''' + approval_question_answer[0][0] + '''</td>
+                            </tr>
+                        </tbody>
+                    </table>
+                    <hr class=\"main_hr\">
+                '''
+    else:
+        div = ''
+
     if flask.request.args.get('plus', None):
         end_check = 1
 
@@ -44,17 +67,17 @@ def give_user_check_2(conn, name):
         if not flask.request.args.get('plus', None):
             div = '<a href="/manager/14?plus=' + url_pas(name) + '">(' + load_lang('compare') + ')</a><hr class=\"main_hr\">'
         else:
-            div = '<a href="/check/' + url_pas(name) + '">(' + name + ')</a> <a href="/check/' + url_pas(flask.request.args.get('plus', None)) + '">(' + flask.request.args.get('plus', None) + ')</a><hr class=\"main_hr\">'
+            div = '<a href="/check/' + url_pas(name) + '">(' + name + ')</a> <a href="/check/' + url_pas(flask.request.args.get('plus', None)) + '">(' + flask.request.args.get('plus', None) + ')</a><hr class=\"main_hr\">' + div
 
-        div +=  '''
-                <table id="main_table_set">
-                    <tbody>
-                        <tr>
-                            <td id="main_table_width">''' + load_lang('name') + '''</td>
-                            <td id="main_table_width">ip</td>
-                            <td id="main_table_width">''' + load_lang('time') + '''</td>
-                        </tr>
-                '''
+        div += '''
+            <table id="main_table_set">
+                <tbody>
+                    <tr>
+                        <td id="main_table_width">''' + load_lang('name') + '''</td>
+                        <td id="main_table_width">ip</td>
+                        <td id="main_table_width">''' + load_lang('time') + '''</td>
+                    </tr>
+        '''
 
         for data in record:
             if data[2]:
@@ -89,4 +112,4 @@ def give_user_check_2(conn, name):
         imp = [load_lang('check'), wiki_set(), custom(), other2([0, 0])],
         data = div,
         menu = [['manager', load_lang('return')]]
-    ))
+    ))

+ 1 - 8
route/inter_wiki.py

@@ -17,14 +17,7 @@ def inter_wiki_2(conn, tools):
         del_link = 'del_email_filter'
         plus_link = 'plus_email_filter'
         title = load_lang('email_filter_list')
-        div = '''
-            <ul>
-                <li>gmail.com</li>
-                <li>naver.com</li>
-                <li>daum.net</li>
-                <li>kakao.com</li>
-            </ul>
-        '''
+        div = ''
 
         curs.execute(db_change("select html from html_filter where kind = 'email'"))
     elif tools == 'name_filter':

+ 7 - 2
route/list_give.py

@@ -10,8 +10,13 @@ def list_give_2(conn):
     for data in curs.fetchall():
         if back != data[0]:
             back = data[0]
+            
+        if admin_check(None) == 1:
+            delGroupLnk = ' <a href="/delete_admin_group/' + url_pas(data[0]) + '">(' + load_lang("delete") + ')</a>'
+        else:
+            delGroupLnk = ""
 
-        list_data += '<li><a href="/admin_plus/' + url_pas(data[0]) + '">' + data[0] + '</a></li>'
+        list_data += '<li><a href="/admin_plus/' + url_pas(data[0]) + '">' + data[0] + '</a>' + delGroupLnk + '</li>'
 
     list_data += '</ul><hr class=\"main_hr\"><a href="/manager/8">(' + load_lang('add') + ')</a>'
 
@@ -19,4 +24,4 @@ def list_give_2(conn):
         imp = [load_lang('admin_group_list'), wiki_set(), custom(), other2([0, 0])],
         data = list_data,
         menu = [['manager', load_lang('return')]]
-    ))    
+    ))    

+ 2 - 2
route/list_old_page.py

@@ -18,8 +18,8 @@ def list_old_page_2(conn):
     curs.execute(db_change('' + \
         'select title, date from history h ' + \
         "where title not like 'user:%' and title not like 'category:%' and title not like 'file:%' and " + \
-        "exists (select title from data where title = h.title) " + \
-        "and not exists (select title from back where link = h.title and type = 'redirect') " + \
+        "exists (select title from data where title = h.title) and " + \
+        "not exists (select title from back where link = h.title and type = 'redirect') " + \
         'group by title ' + \
         'order by date asc ' + \
         'limit ?, 50' + \

+ 35 - 6
route/login_check_key.py

@@ -50,12 +50,41 @@ def login_check_key_2(conn, tool):
 
                         first = 1
                     else:
-                        curs.execute(db_change("insert into user (id, pw, acl, date, encode) values (?, ?, 'user', ?, ?)"), [
-                            flask.session['c_id'],
-                            flask.session['c_pw'],
-                            get_time(),
-                            db_data[0][0]
-                        ])
+                        curs.execute(db_change('select data from other where name = "requires_approval"'))
+                        requires_approval = curs.fetchall()
+                        if requires_approval and requires_approval[0][0] == 'on':
+                            application_token = ''.join(random.choice("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") for i in range(60))
+                            curs.execute(db_change(
+                                "insert into user_application (id, pw, date, encode, question, answer, token, ip, ua, email) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"
+                            ), [
+                                flask.session['c_id'],
+                                flask.session['c_pw'],
+                                get_time(),
+                                db_data[0][0],
+                                flask.session['c_question'],
+                                flask.session['c_ans'],
+                                application_token,
+                                ip,
+                                flask.request.headers.get('User-Agent'),
+                                flask.session['c_email']
+                            ])
+                            conn.commit()
+
+                            flask.session.pop('c_id', None)
+                            flask.session.pop('c_pw', None)
+                            flask.session.pop('c_key', None)
+                            flask.session.pop('c_email', None)
+                            flask.session.pop('c_question', None)
+                            flask.session.pop('c_ans', None)
+
+                            return redirect('/application_submitted')
+                        else:
+                            curs.execute(db_change("insert into user (id, pw, acl, date, encode) values (?, ?, 'user', ?, ?)"), [
+                                flask.session['c_id'],
+                                flask.session['c_pw'],
+                                get_time(),
+                                db_data[0][0]
+                            ])
 
                         first = 0
 

+ 1 - 2
route/login_need_email.py

@@ -39,13 +39,12 @@ def login_need_email_2(conn, tool):
                 flask.session['c_pw'] = ''
 
             if 'c_id' in flask.session:
-                main_email = ['naver.com', 'gmail.com', 'daum.net', 'kakao.com']
                 data = re.search('@([^@]+)$', flask.request.form.get('email', ''))
                 if data:
                     data = data.groups()[0]
 
                     curs.execute(db_change("select html from html_filter where html = ? and kind = 'email'"), [data])
-                    if curs.fetchall() or (data in main_email):
+                    if curs.fetchall():
                         curs.execute(db_change('select id from user_set where name = "email" and data = ?'), [flask.request.form.get('email', '')])
                         if curs.fetchall():
                             flask.session.pop('c_id', None)

+ 75 - 18
route/login_register.py

@@ -23,7 +23,7 @@ def login_register_2(conn):
             captcha_post('', 0)
 
         if flask.request.form.get('id', None) == '' or flask.request.form.get('pw', None) == '':
-            return redirect('/register')
+            return re_error('/error/27')
 
         if flask.request.form.get('pw', None) != flask.request.form.get('pw2', None):
             return re_error('/error/20')
@@ -47,12 +47,28 @@ def login_register_2(conn):
 
         hashed = pw_encode(flask.request.form.get('pw', None))
 
+        curs.execute(db_change('select data from other where name = "requires_approval"'))
+        requires_approval = curs.fetchall()
+        requires_approval = requires_approval and requires_approval[0][0] == 'on'
+
+        approval_question = ''
+        if requires_approval:
+            curs.execute(db_change('select data from other where name = "approval_question"'))
+            approval_question = curs.fetchall()
+            if approval_question and approval_question[0][0]:
+                approval_question = approval_question[0][0]
+            else:
+                approval_question = ''
+
         curs.execute(db_change('select data from other where name = "email_have"'))
         sql_data = curs.fetchall()
         if sql_data and sql_data[0][0] != '':
             flask.session['c_id'] = flask.request.form.get('id', None)
             flask.session['c_pw'] = hashed
             flask.session['c_key'] = ''.join(random.choice("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") for i in range(16))
+            if requires_approval:
+                flask.session['c_ans'] = flask.request.form.get('approval_question_answer')
+                flask.session['c_question'] = approval_question
 
             return redirect('/need_email')
         else:
@@ -61,11 +77,35 @@ def login_register_2(conn):
 
             curs.execute(db_change("select id from user limit 1"))
             if not curs.fetchall():
-                curs.execute(db_change("insert into user (id, pw, acl, date, encode) values (?, ?, 'owner', ?, ?)"), [flask.request.form.get('id', None), hashed, get_time(), db_data[0][0]])
+                curs.execute(db_change("insert into user (id, pw, acl, date, encode) values (?, ?, 'owner', ?, ?)"), [
+                    flask.request.form.get('id', None), 
+                    hashed, 
+                    get_time(), 
+                    db_data[0][0]
+                ])
 
                 first = 1
             else:
-                curs.execute(db_change("insert into user (id, pw, acl, date, encode) values (?, ?, 'user', ?, ?)"), [flask.request.form.get('id', None), hashed, get_time(), db_data[0][0]])
+                if requires_approval:
+                    application_token = ''.join(random.choice("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") for i in range(60))
+                    curs.execute(db_change(
+                        "insert into user_application (id, pw, date, encode, question, answer, token, ip, ua, email) values (?, ?, ?, ?, ?, ?, ?, ?, ?, '')"
+                    ), [
+                        flask.request.form.get('id', None), 
+                        hashed, 
+                        get_time(), 
+                        db_data[0][0], 
+                        approval_question, 
+                        flask.request.form.get('approval_question_answer', None), 
+                        application_token, 
+                        ip_check(), 
+                        flask.request.headers.get('User-Agent')
+                    ])
+                    conn.commit()
+                    
+                    return redirect('/application_submitted')
+                else:
+                    curs.execute(db_change("insert into user (id, pw, acl, date, encode) values (?, ?, 'user', ?, ?)"), [flask.request.form.get('id', None), hashed, get_time(), db_data[0][0]])
 
                 first = 0
 
@@ -93,22 +133,39 @@ def login_register_2(conn):
             contract = data[0][0] + '<hr class=\"main_hr\">'
 
         http_warring = '<hr class=\"main_hr\"><span>' + load_lang('http_warring') + '</span>'
+        approval_question = ''
+        
+        curs.execute(db_change('select data from other where name = "requires_approval"'))
+        requires_approval = curs.fetchall()
+        requires_approval = requires_approval and requires_approval[0][0] == 'on'
+        if requires_approval:
+            curs.execute(db_change('select data from other where name = "approval_question"'))
+            data = curs.fetchall()
+            if data and data[0][0] != '':
+                approval_question = '''
+                    <hr class=\"main_hr\">
+                    <span>''' + load_lang('approval_question') + ' : ' + data[0][0] + '''<span>
+                    <hr class=\"main_hr\">
+                    <input placeholder="''' + load_lang('approval_question') + '''" name="approval_question_answer" type="text">
+                    <hr class=\"main_hr\">
+                '''
 
         return easy_minify(flask.render_template(skin_check(),
             imp = [load_lang('register'), wiki_set(), custom(), other2([0, 0])],
-            data =  '''
-                    <form method="post">
-                        ''' + contract + '''
-                        <input placeholder="''' + load_lang('id') + '''" name="id" type="text">
-                        <hr class=\"main_hr\">
-                        <input placeholder="''' + load_lang('password') + '''" name="pw" type="password">
-                        <hr class=\"main_hr\">
-                        <input placeholder="''' + load_lang('password_confirm') + '''" name="pw2" type="password">
-                        <hr class=\"main_hr\">
-                        ''' + captcha_get() + '''
-                        <button type="submit">''' + load_lang('save') + '''</button>
-                        ''' + http_warring + '''
-                    </form>
-                    ''',
+            data = '''
+                <form method="post">
+                    ''' + contract + '''
+                    <input placeholder="''' + load_lang('id') + '''" name="id" type="text">
+                    <hr class=\"main_hr\">
+                    <input placeholder="''' + load_lang('password') + '''" name="pw" type="password">
+                    <hr class=\"main_hr\">
+                    <input placeholder="''' + load_lang('password_confirm') + '''" name="pw2" type="password">
+                    <hr class=\"main_hr\">
+                    ''' + approval_question + '''
+                    ''' + captcha_get() + '''
+                    <button type="submit">''' + load_lang('save') + '''</button>
+                    ''' + http_warring + '''
+                </form>
+            ''',
             menu = [['user', load_lang('return')]]
-        ))
+        ))

+ 1 - 1
route/main_error_404.py

@@ -4,6 +4,6 @@ def main_error_404_2(conn):
     curs = conn.cursor()
 
     if os.path.exists('404.html') and flask.request.path != '/':
-        return open('404.html', 'r').read()
+        return open('404.html', encoding='utf8').read()
     else:
         return redirect('/w/' + url_pas(wiki_set(2)))

+ 7 - 4
route/main_file.py

@@ -7,14 +7,17 @@ def main_file_2(conn, data):
     if data == 'easter_egg.html':
         return easy_minify(flask.render_template(skin_check(),
             imp = ['easter_egg.html', wiki_set(), custom(), other2([0, 0])],
-            data = open('./views/main_css/file/easter_egg.html', 'r').read(),
+            data = open('./views/main_css/file/easter_egg.html', encoding='utf8').read(),
             menu = 0
         ))
-    elif re.search('\.txt$', data) or data == 'sitemap.xml':
+    elif re.search('\.txt$', data, flags = re.I) or data == 'sitemap.xml':
         if data == 'robots.txt' and not os.path.exists('robots.txt'):
-            return flask.Response('User-agent: *\nDisallow: /\nAllow: /$\nAllow: /w/', mimetype='text/plain')
+            return flask.Response('User-agent: *\nDisallow: /\nAllow: /$\nAllow: /w/', mimetype = 'text/plain')
         elif os.path.exists(data):
-            return flask.send_from_directory('./', data)
+            if re.search('\.txt$', data, flags = re.I):
+                return flask.send_from_directory('./', data, mimetype = 'text/plain')
+            else:
+                return flask.send_from_directory('./', data, mimetype = 'text/xml')
         else:
             return main_error_404.main_error_404_2(conn)
     else:

+ 4 - 1
route/main_image_view.py

@@ -4,6 +4,9 @@ def main_image_view_2(conn, name, app_var):
     curs = conn.cursor()
 
     if os.path.exists(os.path.join(app_var['path_data_image'], name)):
-        return flask.send_from_directory('./' + app_var['path_data_image'], name)
+        return flask.send_from_directory(
+            './' + app_var['path_data_image'], name, 
+            mimetype = 'image/' + re.search('\.([^\.]+)$', name).groups()[0]
+        )
     else:
         return redirect()

+ 16 - 16
route/main_manager.py

@@ -4,20 +4,20 @@ def main_manager_2(conn, num, r_ver):
     curs = conn.cursor()
 
     title_list = {
-        0 : [load_lang('document_name'), 'acl'],
-        1 : [0, 'check'],
-        2 : [load_lang('file_name'), 'plus_file_filter'],
-        3 : [0, 'admin'],
-        4 : [0, 'record'],
-        5 : [0, 'topic_record'],
-        6 : [load_lang('name'), 'admin_plus'],
-        7 : [load_lang('name'), 'plus_edit_filter'],
-        8 : [load_lang('document_name'), 'search'],
-        9 : [0, 'block_user'],
-        10 : [0, 'block_admin'],
-        11 : [load_lang('document_name'), 'watch_list'],
-        12 : [load_lang('compare_target'), 'check'],
-        13 : [load_lang('document_name'), 'edit']
+        0 : [load_lang('document_name'), 'acl', load_lang('acl')],
+        1 : [0, 'check', load_lang('check')],
+        2 : [load_lang('file_name'), 'plus_file_filter', load_lang('file_filter_add')],
+        3 : [0, 'admin', load_lang('authorize')],
+        4 : [0, 'record', load_lang('edit_record')],
+        5 : [0, 'topic_record', load_lang('discussion_record')],
+        6 : [load_lang('name'), 'admin_plus', load_lang('add_admin_group')],
+        7 : [load_lang('name'), 'plus_edit_filter', load_lang('edit_filter_add')],
+        8 : [load_lang('document_name'), 'search', load_lang('search')],
+        9 : [0, 'block_user', load_lang('blocked_user')],
+        10 : [0, 'block_admin', load_lang('blocked_admin')],
+        11 : [load_lang('document_name'), 'watch_list', load_lang('add_watchlist')],
+        12 : [load_lang('compare_target'), 'check', load_lang('compare_target')],
+        13 : [load_lang('document_name'), 'edit', load_lang('edit')]
     }
 
     if num == 1:
@@ -36,6 +36,7 @@ def main_manager_2(conn, num, r_ver):
                     <ul>
                         <li><a href="/give_log">''' + load_lang('admin_group_list') + '''</a></li>
                         <li><a href="/many_delete">''' + load_lang('many_delete') + '''</a></li>
+                        <li><a href="/applications">''' + load_lang('application_list') + '''</a></li>
                         <li><a href="/setting">''' + load_lang('setting') + '''</a></li>
                     </ul>
                     <h3>''' + load_lang('filter') + '''</h3>
@@ -53,7 +54,6 @@ def main_manager_2(conn, num, r_ver):
                     <ul>
                         <li><a href="/restart">''' + load_lang('wiki_restart') + '''</a></li>
                         <li><a href="/update">''' + load_lang('update') + '''</a></li>
-                        <li><a href="/oauth_setting">''' + load_lang('oauth_setting') + '''</a></li>
                         <li><a href="/adsense_setting">''' + load_lang('adsense_setting') + '''</a></li>
                     </ul>
                     <br>
@@ -80,7 +80,7 @@ def main_manager_2(conn, num, r_ver):
                 placeholder = title_list[(num - 2)][0]
 
             return easy_minify(flask.render_template(skin_check(),
-                imp = ['Redirect', wiki_set(), custom(), other2([0, 0])],
+                imp = [title_list[(num - 2)][2], wiki_set(), custom(), other2([0, 0])],
                 data =  '''
                         <form method="post">
                             <input placeholder="''' + placeholder + '''" name="name" type="text">

+ 10 - 1
route/main_views.py

@@ -16,4 +16,13 @@ def main_views_2(conn, name):
         plus = ''
         rename = name
 
-    return flask.send_from_directory('./views' + plus, rename)
+    mime_type = re.search('\.([^\.]+)$', rename).groups()[0]
+    if mime_type:
+        if mime_type in ['.jpeg', '.jpg', '.gif', '.png', '.webp', '.JPEG', '.JPG', '.GIF', '.PNG', '.WEBP']:
+            mime_type = 'image/' + mime_type
+        else:
+            mime_type = 'text/' + mime_type
+    else:
+        mime_type = 'text/plain'
+
+    return flask.send_from_directory('./views' + plus, rename, mimetype = mime_type)

+ 1 - 1
route/recent_changes.py

@@ -198,7 +198,7 @@ def recent_changes_2(conn, name, tool):
                     menu = [['w/' + url_pas(name), load_lang('return')]]
 
                     if admin_check() == 1:
-                        menu += [['add_history/' + url_pas(name), load_lang('add_history')]]
+                        menu += [['add_history/' + url_pas(name), load_lang('history_add')]]
                 else:
                     menu = [['history/' + url_pas(name), load_lang('return')]]
 

+ 2 - 2
route/recent_discuss.py

@@ -40,7 +40,7 @@ def recent_discuss_2(conn):
         title = html.escape(data[0])
         sub = html.escape(data[1])
 
-        div += '<tr><td><a href="/thread/' + get_code + '">' + title + '</a> (' + sub + ')</td><td>' + data[2] + '</td></tr>'
+        div += '<tr><td><a href="/thread/' + get_code + '">' + sub + '</a> (' + title + ')</td><td>' + data[2] + '</td></tr>'
 
     div += '</tbody></table>'
 
@@ -48,4 +48,4 @@ def recent_discuss_2(conn):
         imp = [load_lang('recent_discussion'), wiki_set(), custom(), other2([m_sub, 0])],
         data = div,
         menu = 0
-    ))
+    ))

+ 10 - 9
route/search_deep.py

@@ -23,15 +23,16 @@ def search_deep_2(conn, name):
     else:
         link_id = 'id="not_thing"'
 
-    div =   '''
-            <ul>
-                <li>
-                    <a ''' + link_id + ' href="/w/' + url_pas(name) + '">' + name + '''</a>
-                </li>
-            </ul>
-            <hr class=\"main_hr\">
-            <ul>
-            '''
+    div = '''
+        <ul>
+            <li>
+                <a ''' + link_id + ' href="/w/' + url_pas(name) + '">' + html.escape(name) + '''</a>
+            </li>
+        </ul>
+        <hr class=\"main_hr\">
+        <ul>
+    '''
+
     curs.execute(db_change('select data from other where name = "count_all_title"'))
     if int(curs.fetchall()[0][0]) < 30000:
         curs.execute(db_change("" + \

+ 168 - 52
route/setting.py

@@ -15,7 +15,8 @@ def setting_2(conn, num):
             'robots.txt',
             'Google',
             load_lang('main_bottom_body'),
-            load_lang('main_acl_setting')
+            load_lang('main_acl_setting'),
+            load_lang('oauth_setting')
         ]
 
         x = 0
@@ -47,13 +48,14 @@ def setting_2(conn, num):
             13 : 'email_have',
             15 : 'encode',
             16 : 'host',
-            19 : 'slow_edit'
+            19 : 'slow_edit',
+            20 : 'requires_approval',
         }
         n_list = {
             0 : 'Wiki',
             1 : '',
             2 : 'FrontPage',
-            3 : 'CC 0',
+            3 : 'ARR',
             4 : '2',
             5 : '',
             7 : '',
@@ -65,7 +67,8 @@ def setting_2(conn, num):
             13 : '',
             15 : 'sha3',
             16 : '0.0.0.0',
-            19 : '0'
+            19 : '0',
+            20 : ''
         }
 
         if flask.request.method == 'POST':
@@ -103,14 +106,16 @@ def setting_2(conn, num):
                 else:
                     acl_div[0] += '<option value="' + acl_data + '">' + acl_data + '</option>'
 
-            check_box_div = ['', '', '']
-            for i in range(0, 3):
+            check_box_div = ['', '', '', '']
+            for i in range(0, 4):
                 if i == 0:
                     acl_num = 7
                 elif i == 1:
                     acl_num = 8
-                else:
+                elif i == 2:
                     acl_num = 13
+                else:
+                    acl_num = 20
 
                 if d_list[acl_num]:
                     check_box_div[i] = 'checked="checked"'
@@ -130,57 +135,59 @@ def setting_2(conn, num):
                         <span>''' + load_lang('wiki_name') + '''</span>
                         <hr class=\"main_hr\">
                         <input type="text" name="name" value="''' + html.escape(d_list[0]) + '''">
-                        <hr class=\"main_hr\">
+                        <hr>
                         <span>''' + load_lang('wiki_logo') + ''' (HTML)</span>
                         <hr class=\"main_hr\">
                         <input type="text" name="logo" value="''' + html.escape(d_list[1]) + '''">
-                        <hr class=\"main_hr\">
+                        <hr>
                         <span>''' + load_lang('main_page') + '''</span>
                         <hr class=\"main_hr\">
                         <input type="text" name="frontpage" value="''' + html.escape(d_list[2]) + '''">
-                        <hr class=\"main_hr\">
+                        <hr>
                         <span>''' + load_lang('bottom_text') + ''' (HTML)</span>
                         <hr class=\"main_hr\">
                         <input type="text" name="license" value="''' + html.escape(d_list[3]) + '''">
-                        <hr class=\"main_hr\">
+                        <hr>
                         <span>''' + load_lang('max_file_size') + ''' (MB)</span>
                         <hr class=\"main_hr\">
                         <input type="text" name="upload" value="''' + html.escape(d_list[4]) + '''">
-                        <hr class=\"main_hr\">
+                        <hr>
                         <span>''' + load_lang('backup_interval') + ' (' + load_lang('hour') + ') (' + load_lang('off') + ' : 0) (' + load_lang('sqlite_only') + ') (' + load_lang('restart_required') + ''')</span>
                         <hr class=\"main_hr\">
                         <input type="text" name="back_up" value="''' + html.escape(d_list[9]) + '''">
-                        <hr class=\"main_hr\">
+                        <hr>
                         <span>''' + load_lang('wiki_skin') + '''</span>
                         <hr class=\"main_hr\">
                         <select name="skin">''' + load_skin(d_list[5]) + '''</select>
-                        <hr class=\"main_hr\">
+                        <hr>
                         <input type="checkbox" name="reg" ''' + check_box_div[0] + '''> ''' + load_lang('no_register') + '''
                         <hr class=\"main_hr\">
                         <input type="checkbox" name="ip_view" ''' + check_box_div[1] + '''> ''' + load_lang('hide_ip') + '''
                         <hr class=\"main_hr\">
-                        <input type="checkbox" name="email_have" ''' + check_box_div[2] + '''> ''' + load_lang('email_required') + ' <a href="/setting/6">(' + load_lang('google_imap_required') + ''')</a>
+                        <input type="checkbox" name="email_have" ''' + check_box_div[2] + '''> ''' + load_lang('email_required') + ' <a href="/setting/6">(' + load_lang('smtp_setting_required') + ''')</a>
                         <hr class=\"main_hr\">
+                        <input type="checkbox" name="requires_approval" ''' + check_box_div[3] + '''> ''' + load_lang('requires_approval') + '''
+                        <hr>
                         <span>''' + load_lang('wiki_host') + '''</span>
                         <hr class=\"main_hr\">
                         <input type="text" name="host" value="''' + html.escape(d_list[16]) + '''">
-                        <hr class=\"main_hr\">
+                        <hr>
                         <span>''' + load_lang('wiki_port') + '''</span>
                         <hr class=\"main_hr\">
                         <input type="text" name="port" value="''' + html.escape(d_list[10]) + '''">
-                        <hr class=\"main_hr\">
+                        <hr>
                         <span>''' + load_lang('wiki_secret_key') + '''</span>
                         <hr class=\"main_hr\">
                         <input type="password" name="key" value="''' + html.escape(d_list[11]) + '''">
-                        <hr class=\"main_hr\">
+                        <hr>
                         <span>''' + load_lang('update_branch') + '''</span>
                         <hr class=\"main_hr\">
                         <select name="update">''' + branch_div + '''</select>
-                        <hr class=\"main_hr\">
+                        <hr>
                         <span>''' + load_lang('encryption_method') + '''</span>
                         <hr class=\"main_hr\">
                         <select name="encode">''' + acl_div[0] + '''</select>
-                        <hr class=\"main_hr\">
+                        <hr>
                         <span>''' + load_lang('slow_edit') + ' (' + load_lang('second') + ') (' + load_lang('off') + ''' : 0)</span>
                         <hr class=\"main_hr\">
                         <input name="''' + i_list[19] + '''" value="''' + html.escape(d_list[19]) + '''">
@@ -203,7 +210,8 @@ def setting_2(conn, num):
             'reset_user_text',
             'error_401',
             'error_404',
-            'edit_help'
+            'edit_help',
+            'approval_question'
         ]
         if flask.request.method == 'POST':
             for i in i_list:
@@ -239,52 +247,60 @@ def setting_2(conn, num):
                         <span>''' + load_lang('register_text') + ''' (HTML)</span>
                         <hr class=\"main_hr\">
                         <input name="''' + i_list[0] + '''" value="''' + html.escape(d_list[0]) + '''">
-                        <hr class=\"main_hr\">
+                        <hr>
                         <span>''' + load_lang('non_login_alert') + ''' (HTML)</span>
                         <hr class=\"main_hr\">
                         <input name="''' + i_list[1] + '''" value="''' + html.escape(d_list[1]) + '''">
-                        <hr class=\"main_hr\">
+                        <hr>
                         <span>''' + load_lang('edit_bottom_text') + ''' (HTML)</span>
                         <hr class=\"main_hr\">
                         <input name="''' + i_list[2] + '''" value="''' + html.escape(d_list[2]) + '''">
-                        <hr class=\"main_hr\">
+                        <hr>
                         <span>''' + load_lang('check_key_text') + ''' (HTML)</span>
                         <hr class=\"main_hr\">
                         <input name="''' + i_list[3] + '''" value="''' + html.escape(d_list[3]) + '''">
-                        <hr class=\"main_hr\">
+                        <hr>
                         <span>''' + load_lang('email_title') + '''</span>
                         <hr class=\"main_hr\">
                         <input name="''' + i_list[4] + '''" value="''' + html.escape(d_list[4]) + '''">
-                        <hr class=\"main_hr\">
+                        <hr>
                         <span>''' + load_lang('email_text') + '''</span>
                         <hr class=\"main_hr\">
                         <input name="''' + i_list[5] + '''" value="''' + html.escape(d_list[5]) + '''">
-                        <hr class=\"main_hr\">
+                        <hr>
                         <span>''' + load_lang('email_insert_text') + '''</span>
                         <hr class=\"main_hr\">
                         <input name="''' + i_list[6] + '''" value="''' + html.escape(d_list[6]) + '''">
-                        <hr class=\"main_hr\">
+                        <hr>
                         <span>''' + load_lang('password_search_text') + '''</span>
                         <hr class=\"main_hr\">
                         <input name="''' + i_list[7] + '''" value="''' + html.escape(d_list[7]) + '''">
-                        <hr class=\"main_hr\">
+                        <hr>
                         <span>''' + load_lang('reset_user_text') + '''</span>
                         <hr class=\"main_hr\">
                         <input name="''' + i_list[8] + '''" value="''' + html.escape(d_list[8]) + '''">
-                        <hr class=\"main_hr\">
+                        <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\">
+                        <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\">
+                        <hr>
                         <span>''' + load_lang('edit_help') + '''</span>
                         <hr class=\"main_hr\">
                         <input name="''' + i_list[11] + '''" value="''' + html.escape(d_list[11]) + '''">
+                        <hr>
+                        <span>''' + load_lang('approval_question') + '''</span> <a href="#rfn-1" id="fn-1">(1)</a>
+                        <hr class=\"main_hr\">
+                        <input name="''' + i_list[12] + '''" value="''' + html.escape(d_list[12]) + '''">
                         <hr class=\"main_hr\">
                         <button id="save" type="submit">''' + load_lang('save') + '''</button>
+                        <hr>
+                        <ul>
+                            <li><a href="#fn-1" id="rfn-1">(1)</a> <span>''' + load_lang('approval_question_visible_only_when_approval_on') + '''</span></li>
+                        </ul>
                     </form>
                 ''',
                 menu = [['setting', load_lang('return')]]
@@ -387,7 +403,7 @@ def setting_2(conn, num):
 
             conn.commit()
 
-            fw = open('./robots.txt', 'w')
+            fw = open('./robots.txt', 'w', encoding='utf8')
             fw.write(re.sub('\r\n', '\n', flask.request.form.get('content', '')))
             fw.close()
 
@@ -399,11 +415,11 @@ def setting_2(conn, num):
                 curs.execute(db_change('select data from other where name = "robot"'))
                 robot_test = curs.fetchall()
                 if robot_test:
-                    fw_test = open('./robots.txt', 'w')
+                    fw_test = open('./robots.txt', 'w', encoding='utf8')
                     fw_test.write(re.sub('\r\n', '\n', robot_test[0][0]))
                     fw_test.close()
                 else:
-                    fw_test = open('./robots.txt', 'w')
+                    fw_test = open('./robots.txt', 'w', encoding='utf8')
                     fw_test.write('User-agent: *\nDisallow: /\nAllow: /$\nAllow: /w/')
                     fw_test.close()
 
@@ -416,7 +432,7 @@ def setting_2(conn, num):
             else:
                 data = ''
 
-            f = open('./robots.txt', 'r')
+            f = open('./robots.txt', encoding='utf8')
             lines = f.readlines()
             f.close()
 
@@ -440,16 +456,16 @@ def setting_2(conn, num):
         i_list = [
             'recaptcha',
             'sec_re',
-            'g_email',
-            'g_pass'
+            'smtp_server',
+            'smtp_port',
+            'smtp_security',
+            'smtp_email',
+            'smtp_pass'
         ]
 
         if flask.request.method == 'POST':
             for data in i_list:
-                if data == 'g_email':
-                    into_data = re.sub('@.*$', '', flask.request.form.get(data, ''))
-                else:
-                    into_data = flask.request.form.get(data, '')
+                into_data = flask.request.form.get(data, '')
 
                 curs.execute(db_change("update other set data = ? where name = ?"), [into_data, data])
 
@@ -477,6 +493,10 @@ def setting_2(conn, num):
 
             conn.commit()
 
+            security_radios = ''
+            for i in ['tls', 'starttls', 'plain']:
+                security_radios += '<input name="smtp_security" type="radio" value="' + i + '" ' + ('checked' if d_list[4] == i else '') + '>' + i + '<hr class="main_hr">'
+
             return easy_minify(flask.render_template(skin_check(),
                 imp = ['Google', wiki_set(), custom(), other2([0, 0])],
                 data = '''
@@ -485,19 +505,31 @@ def setting_2(conn, num):
                         <span>HTML</span>
                         <hr class=\"main_hr\">
                         <input name="recaptcha" placeholder='&lt;div class="g-recaptcha" data-sitekey="''' + load_lang('public_key') + '''"&gt;&lt;/div&gt;' value="''' + html.escape(d_list[0]) + '''">
-                        <hr class=\"main_hr\">
+                        <hr>
                         <span>''' + load_lang('secret_key') + '''</span>
                         <hr class=\"main_hr\">
                         <input name="sec_re" value="''' + html.escape(d_list[1]) + '''">
                         <hr class=\"main_hr\">
-                        <h2><a href="https://support.google.com/mail/answer/7126229">''' + load_lang('google_imap') + '</a> (' + load_lang('restart_required') + ''')</h1>
-                        <span>''' + load_lang('google_email') + '''</span>
+                        <h2>''' + load_lang('smtp_setting') + ' (' + load_lang('restart_required') + ''')</h1>
+                        <span>''' + load_lang('smtp_server') + '''</span>
+                        <hr class=\"main_hr\">
+                        <input name="smtp_server" value="''' + html.escape(d_list[2]) + '''">
+                        <hr class=\"main_hr\">
+                        <span>''' + load_lang('smtp_port') + '''</span>
+                        <hr class=\"main_hr\">
+                        <input name="smtp_port" value="''' + html.escape(d_list[3]) + '''">
+                        <hr class=\"main_hr\">
+                        <span>''' + load_lang('smtp_security') + '''</span>
+                        <hr class=\"main_hr\">'''
+                        + security_radios +
+                        '''<hr class=\"main_hr\">
+                        <span>''' + load_lang('smtp_username') + '''</span>
                         <hr class=\"main_hr\">
-                        <input name="g_email" value="''' + html.escape(d_list[2]) + '''">
+                        <input name="smtp_email" value="''' + html.escape(d_list[5]) + '''">
                         <hr class=\"main_hr\">
-                        <span><a href="https://security.google.com/settings/security/apppasswords">''' + load_lang('google_app_password') + '''</a></span>
+                        <span>''' + load_lang('smtp_password') + '''</span>
                         <hr class=\"main_hr\">
-                        <input type="password" name="g_pass" value="''' + html.escape(d_list[3]) + '''">
+                        <input type="password" name="smtp_pass" value="''' + html.escape(d_list[6]) + '''">
                         <hr class=\"main_hr\">
                         <button id="save" type="submit">''' + load_lang('save') + '''</button>
                     </form>
@@ -563,19 +595,19 @@ def setting_2(conn, num):
                         <span>''' + load_lang('document_acl') + '</span> <a href="/acl/TEST">(' + load_lang('reference') + ''')</a>
                         <hr class=\"main_hr\">
                         <select name="edit">''' + acl_div[0] + '''</select>
-                        <hr class=\"main_hr\">
+                        <hr>
                         <span>''' + load_lang('discussion_acl') + '''</span>
                         <hr class=\"main_hr\">
                         <select name="discussion">''' + acl_div[1] + '''</select>
-                        <hr class=\"main_hr\">
+                        <hr>
                         <span>''' + load_lang('upload_acl') + '''</span>
                         <hr class=\"main_hr\">
                         <select name="upload_acl">''' + acl_div[2] + '''</select>
-                        <hr class=\"main_hr\">
+                        <hr>
                         <span>''' + load_lang('view_acl') + '''</span>
                         <hr class=\"main_hr\">
                         <select name="all_view_acl">''' + acl_div[3] + '''</select>
-                        <hr class=\"main_hr\">
+                        <hr>
                         <span>''' + load_lang('edit_req_acl') + '''</span>
                         <hr class=\"main_hr\">
                         <select name="edit_req_acl">''' + acl_div[4] + '''</select>
@@ -585,5 +617,89 @@ def setting_2(conn, num):
                 ''',
                 menu = [['setting', load_lang('return')]]
             ))
+    elif num == 9:
+        oauth_supported = load_oauth('_README')['support']
+
+        if admin_check() != 1:
+            return re_error('/error/3')
+
+        if flask.request.method == 'POST':
+            admin_check(None, 'oauth setting')
+            return_json_data = '{ "publish_url" : "' + flask.request.form.get('publish_url_box', '') + '", '
+
+            for i in range(len(oauth_supported)):
+                return_json_data += '"' + oauth_supported[i] + '" : { '
+                for j in range(2):
+                    if j == 0:
+                        load_target = 'id'
+                    elif j == 1:
+                        load_target = 'secret'
+
+                    target_data = flask.request.form.get(oauth_supported[i] + '_client_' + load_target, '')
+                    return_json_data += '"client_' + load_target  + '" : "' + target_data + '"' + (',' if j == 0 else '')
+
+                return_json_data += ' }'
+
+                try:
+                    _ = oauth_supported[i + 1]
+
+                    return_json_data += ', '
+                except:
+                    return_json_data += ' }'
+
+            with open(app_var['path_oauth_setting'], 'w', encoding='utf8') as f:
+                f.write(return_json_data)
+
+            return redirect('/oauth_setting')
+        else:
+            body_content = load_lang('oauth_explain') + '<hr>'
+            body_content += '''
+                <input placeholder="publish_url" id="publish_url_box" name="publish_url_box">
+                <hr>
+                <script>
+                    function check_value (target) {
+                        target_box = document.getElementById(target.id + "_box");
+                        if (target.value !== "") {
+                            target_box.checked = true;
+                        } else {
+                            target_box.checked = false;
+                        }
+                    }
+                </script>
+            '''
+
+            init_js = ''
+            body_content += '<form method="post">'
+
+            for i in range(len(oauth_supported)):
+                oauth_data = load_oauth(oauth_supported[i])
+
+                for j in range(2):
+                    if j == 0:
+                        load_target = 'id'
+                    elif j == 1:
+                        load_target = 'secret'
+
+                    init_js += 'check_value(document.getElementById("' + oauth_supported[i] + '_client_' + load_target + '"));'
+                    body_content += '''
+                        <input id="''' + oauth_supported[i] + '''_client_''' + load_target + '''_box" type="checkbox" disabled>
+                        <input  placeholder="''' + oauth_supported[i] + '''_client_''' + load_target + '''" 
+                                id="''' + oauth_supported[i] + '''_client_''' + load_target + '''" 
+                                name="''' + oauth_supported[i] + '''_client_''' + load_target + '''" 
+                                value="''' + oauth_data['client_' + load_target] + '''" 
+                                type="text" 
+                                onChange="check_value(this)" 
+                                style="width: 80%;">
+                        ''' + ('<hr>' if j == 1 else '<hr class=\"main_hr\">') + '''
+                    '''
+
+            body_content += '<button id="save" type="submit">' + load_lang('save') + '</button></form>'
+            body_content += '<script>' + init_js + '</script>'
+
+            return easy_minify(flask.render_template(skin_check(),
+                imp = [load_lang('oauth_setting'), wiki_set(), custom(), other2([0, 0])],
+                data = body_content,
+                menu = [['other', load_lang('return')]]
+            ))
     else:
         return redirect()

+ 0 - 100
route/setting_oauth.py

@@ -1,100 +0,0 @@
-from .tool.func import *
-
-def setting_oauth_2(conn):
-    curs = conn.cursor()
-
-    if admin_check(None, 'oauth setting') != 1:
-        return re_error('/error/3')
-
-    if flask.request.method == 'POST':
-        try:
-            facebook_client_id = flask.request.form['facebook_client_id']
-            facebook_client_secret = flask.request.form['facebook_client_secret']
-
-            naver_client_id = flask.request.form['naver_client_id']
-            naver_client_secret = flask.request.form['naver_client_secret']
-        except:
-            return easy_minify(flask.render_template(skin_check(),
-                imp = [load_lang('inter_error'), wiki_set(), custom(), other2([0, 0])],
-                data = '<h2>ie_no_data_required</h2>' + load_lang('ie_no_data_required'),
-                menu = [['other', load_lang('return')]]
-            ))
-
-        with open(app_var['path_oauth_setting'], 'r', encoding='utf-8') as f:
-            legacy = json.loads(f.read())
-
-        with open(app_var['path_oauth_setting'], 'w', encoding='utf-8') as f:
-            f.write('''
-                {
-                    "_README" : {
-                        "en" : "''' + legacy['_README']['en'] + '''",
-                        "ko" : "''' + legacy['_README']['ko'] + '''",
-                        "support" : ''' + str(legacy['_README']['support']).replace("'", '"') + '''
-                    },
-                    "publish_url" : "''' + legacy['publish_url'] + '''",
-                    "facebook" : {
-                        "client_id" : "''' + facebook_client_id + '''",
-                        "client_secret" : "''' + facebook_client_secret + '''"
-                    },
-                    "naver" : {
-                        "client_id" : "''' + naver_client_id + '''",
-                        "client_secret" : "''' + naver_client_secret + '''"
-                    }
-                }
-            ''')
-
-        return flask.redirect('/oauth_setting')
-
-    oauth_supported = load_oauth('_README')['support']
-
-    body_content = ''
-    body_content += '''
-        <script>
-            function check_value (target) {
-                target_box = document.getElementById(target.id + "_box");
-                if (target.value !== "") {
-                    target_box.checked = true;
-                } else {
-                    target_box.checked = false;
-                }
-            }
-        </script>
-    '''
-
-    init_js = ''
-    body_content += '<form method="post">'
-
-    for i in range(len(oauth_supported)):
-        oauth_data = load_oauth(oauth_supported[i])
-        for j in range(2):
-            if j == 0:
-                load_target = 'id'
-            elif j == 1:
-                load_target = 'secret'
-
-            init_js += 'check_value(document.getElementById("{}_client_{}"));'.format(oauth_supported[i], load_target)
-
-            body_content += '''
-                <input id="{}_client_{}_box" type="checkbox" disabled>
-                <input placeholder="{}_client_{}" id="{}_client_{}" name="{}_client_{}" value="{}" type="text" onChange="check_value(this)" style="width: 80%;">
-                <hr>
-            '''.format(
-                oauth_supported[i],
-                load_target,
-                oauth_supported[i],
-                load_target,
-                oauth_supported[i],
-                load_target,
-                oauth_supported[i],
-                load_target,
-                oauth_data['client_{}'.format(load_target)]
-            )
-
-    body_content += '<button id="save" type="submit">' + load_lang('save') + '</button></form>'
-    body_content += '<script>' + init_js + '</script>'
-
-    return easy_minify(flask.render_template(skin_check(),
-        imp = [load_lang('oauth_setting'), wiki_set(), custom(), other2([0, 0])],
-        data = body_content,
-        menu = [['other', load_lang('return')]]
-    ))

+ 129 - 99
route/tool/func.py

@@ -4,6 +4,7 @@ import platform
 
 for i in range(0, 2):
     try:
+        from diff_match_patch import diff_match_patch
         import werkzeug.routing
         import werkzeug.debug
         import flask_compress
@@ -19,7 +20,6 @@ for i in range(0, 2):
         import smtplib
         import bcrypt
         import zipfile
-        import difflib
         import shutil
         import threading
         import logging
@@ -60,7 +60,7 @@ for i in range(0, 2):
             print(e)
             raise
 
-app_var = json.loads(open('data/app_var.json', encoding='utf-8').read())
+app_var = json.loads(open('data/app_var.json', encoding='utf8').read())
 
 def load_conn(data):
     global conn
@@ -72,25 +72,46 @@ def load_conn(data):
     load_conn2(data)
 
 def send_email(who, title, data):
-    smtp = smtplib.SMTP_SSL('smtp.gmail.com', 465)
-
     try:
-        curs.execute(db_change('select name, data from other where name = "g_email" or name = "g_pass"'))
+        curs.execute(db_change('select name, data from other where name = "smtp_email" or name = "smtp_pass" or name = "smtp_server" or name = "smtp_port" or name = "smtp_security"'))
         rep_data = curs.fetchall()
+
+        smtp_email = ''
+        smtp_pass = ''
+        smtp_server = ''
+        smtp_security = ''
+        smtp_port = ''
+        smtp = ''
+
         if rep_data:
-            g_email = ''
-            g_pass = ''
+            smtp_email = ''
+            smtp_pass = ''
             for i in rep_data:
-                if i[0] == 'g_email':
-                    g_email = i[1]
-                else:
-                    g_pass = i[1]
-
-            smtp.login(g_email, g_pass)
+                if i[0] == 'smtp_email':
+                    smtp_email = i[1]
+                elif i[0] == 'smtp_pass':
+                    smtp_pass = i[1]
+                elif i[0] == 'smtp_server':
+                    smtp_server = i[1]
+                elif i[0] == 'smtp_security':
+                    smtp_security = i[1]
+                elif i[0] == 'smtp_port':
+                    smtp_port = i[1]
+            
+            smtp_port = int(smtp_port)
+            if smtp_security == 'plain':
+                smtp = smtplib.SMTP(smtp_server, smtp_port)
+            elif smtp_security == 'starttls':
+                smtp = smtplib.SMTP(smtp_server, smtp_port)
+                smtp.starttls()
+            else: # if smtp_security == 'tls':
+                smtp = smtplib.SMTP_SSL(smtp_server, smtp_port)
+            
+            smtp.login(smtp_email, smtp_pass)
 
         msg = email.mime.text.MIMEText(data)
         msg['Subject'] = title
-        smtp.sendmail(g_email, who, msg.as_string())
+        smtp.sendmail(smtp_email, who, msg.as_string())
 
         smtp.quit()
     except:
@@ -100,7 +121,7 @@ def send_email(who, title, data):
 def last_change(data):
     json_address = re.sub("(((?!\.|\/).)+)\.html$", "set.json", skin_check())
     try:
-        json_data = json.loads(open(json_address).read())
+        json_data = json.loads(open(json_address, encoding='utf8').read())
     except:
         json_data = 0
 
@@ -159,23 +180,45 @@ def captcha_get():
 
     return data
 
-def update():
-    #v3.1.5
+def update(ver_num):
+    print('----')
+    # 업데이트 하위 호환 유지 함수
+    # v3.1.5
     try:
         num = 1
         curs.execute(db_change('select title, sub from topic where id = "1" order by date asc'))
         db_data = curs.fetchall()
-        for i in db_data:
-            curs.execute(db_change("update topic set code = ? where title = ? and sub = ? and id = '1'"), [str(num), i[0], i[1]])
-            num += 1
+        if db_data:
+            for i in db_data:
+                curs.execute(db_change("update topic set code = ? where title = ? and sub = ? and id = '1'"), [str(num), i[0], i[1]])
+                num += 1
 
-        print('----')
-        print('Add topic code')
-        print('----')
+            print('Add topic code')
     except:
         pass
 
+    if ver_num < 3160027:
+        print('Add init set')
+        set_init()
+
+    if ver_num < 3160028:
+        curs.execute(db_change('delete from cache_data'))
+
     conn.commit()
+    print('Update pass')
+    print('----')
+
+def set_init():
+    # 초기값 설정 함수    
+    curs.execute(db_change("select html from html_filter where kind = 'email'"))
+    if not curs.fetchall():
+        for i in ['naver.com', 'gmail.com', 'daum.net', 'kakao.com']:
+            curs.execute(db_change("insert into html_filter (html, kind) values (?, 'email')"), [i])
+
+    curs.execute(db_change('select data from other where name = "smtp_server" or name = "smtp_port" or name = "smtp_security"'))
+    if not curs.fetchall():
+        for i in [['smtp_server', 'imap.google.com'], ['smtp_port', '587'], ['smtp_security', 'tls']]:
+            curs.execute(db_change("insert into other (name, data) values (?, ?)"), [i[0], i[1]])
 
 def topic_change(num):
     curs.execute(db_change('select title, sub from topic where id = "1" and code = ?'), [str(num)])
@@ -275,7 +318,7 @@ def load_lang(data, num = 2, safe = 0):
         curs.execute(db_change("select data from other where name = 'language'"))
         rep_data = curs.fetchall()
 
-        json_data = open(os.path.join('language', rep_data[0][0] + '.json'), 'rt', encoding='utf-8').read()
+        json_data = open(os.path.join('language', rep_data[0][0] + '.json'), encoding='utf8').read()
         lang = json.loads(json_data)
 
         if data in lang:
@@ -290,7 +333,7 @@ def load_lang(data, num = 2, safe = 0):
         rep_data = curs.fetchall()
         if rep_data:
             try:
-                json_data = open(os.path.join('language', rep_data[0][0] + '.json'), 'rt', encoding='utf-8').read()
+                json_data = open(os.path.join('language', rep_data[0][0] + '.json'), encoding='utf8').read()
                 lang = json.loads(json_data)
             except:
                 return load_lang(data, 1, safe)
@@ -306,16 +349,47 @@ def load_lang(data, num = 2, safe = 0):
             return load_lang(data, 1, safe)
 
 def load_oauth(provider):
-    oauth = json.loads(open(app_var['path_oauth_setting'], encoding='utf-8').read())
+    oauth_supported = ["discord", "facebook", "naver", "kakao"]
+    if(provider == '_README'):
+        return { "support" : oauth_supported }
+    else:
+        try:
+            oauth = json.loads(open(app_var['path_oauth_setting'], encoding='utf8').read())
+        except:
+            return_json_data = '{ "publish_url" : "", '
+
+            for i in range(len(oauth_supported)):
+                return_json_data += '"' + oauth_supported[i] + '" : { '
+                for j in range(2):
+                    if j == 0:
+                        load_target = 'id'
+                    elif j == 1:
+                        load_target = 'secret'
+
+                    return_json_data += '"client_' + load_target  + '" : ""' + (',' if j == 0 else '')
+
+                return_json_data += ' }'
+
+                try:
+                    _ = oauth_supported[i + 1]
+
+                    return_json_data += ', '
+                except:
+                    return_json_data += ' }'
+
+            with open(app_var['path_oauth_setting'], 'w', encoding='utf-8') as f:
+                f.write(return_json_data)
+
+            oauth = json.loads(open(app_var['path_oauth_setting'], encoding='utf8').read())
 
-    return oauth[provider]
+        return oauth[provider]
 
 def update_oauth(provider, target, content):
-    oauth = json.loads(open(app_var['path_oauth_setting'], encoding='utf-8').read())
+    oauth = json.loads(open(app_var['path_oauth_setting'], encoding='utf8').read())
     oauth[provider][target] = content
 
-    with open(app_var['path_oauth_setting'], 'w') as f:
-        f.write(json.dumps(oauth, sort_keys=True, indent=4))
+    with open(app_var['path_oauth_setting'], 'w', encoding='utf8') as f:
+        f.write(json.dumps(oauth, sort_keys = True, indent = 4))
 
     return 'Done'
 
@@ -396,16 +470,14 @@ def other2(data):
         data += ['']
 
     req_list = ''
-    main_css_ver = 2
+    main_css_ver = 19
 
     if not 'main_css_load' in flask.session or not 'main_css_ver' in flask.session or flask.session['main_css_ver'] != main_css_ver:
         for i_data in os.listdir(os.path.join("views", "main_css", "css")):
-            file_date = str(int(os.path.getmtime(os.path.join("views", "main_css", "css", i_data))))
-            req_list += '<link rel="stylesheet" href="/views/main_css/css/' + i_data + '?ver=' + file_date + '">'
+            req_list += '<link rel="stylesheet" href="/views/main_css/css/' + i_data + '?ver=' + str(main_css_ver) + '">'
 
         for i_data in os.listdir(os.path.join("views", "main_css", "js")):
-            file_date = str(int(os.path.getmtime(os.path.join("views", "main_css", "js", i_data))))
-            req_list += '<script src="/views/main_css/js/' + i_data + '?ver=' + file_date + '"></script>'
+            req_list += '<script src="/views/main_css/js/' + i_data + '?ver=' + str(main_css_ver) + '"></script>'
 
         flask.session['main_css_load'] = req_list
         flask.session['main_css_ver'] = main_css_ver
@@ -413,7 +485,7 @@ def other2(data):
         req_list = flask.session['main_css_load']
 
     data = data[0:2] + ['', '''
-        <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/styles/default.min.css">
+        <link   rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/styles/default.min.css">
         <link   rel="stylesheet"
                 href="https://cdn.jsdelivr.net/npm/katex@0.10.1/dist/katex.min.css"
                 integrity="sha384-dbVIfZGuN1Yq7/1Ocstc1lUEm+AT+/rCkibIcC/OmWo5f0EA48Vf8CytHzGrSwbQ"
@@ -427,13 +499,20 @@ def other2(data):
     return data
 
 def cut_100(data):
-    data = re.sub('<(((?!>).)*)>', ' ', data)
-    data = re.sub('\n', ' ', data)
-    data = re.sub('^ +', '', data)
-    data = re.sub(' +$', '', data)
-    data = re.sub(' {2,}', ' ', data)
-
-    return data[0:100] + '...'
+    if re.search('^\/w\/', flask.request.path):
+        data = re.sub('<script>((\n*(((?!<\/script>).)+)\n*)+)<\/script>', '', data)
+        data = re.sub('<hr class="main_hr">((\n*((.+)\n*))+)$', '', data)
+        data = re.sub('<div id="cate_all">((\n*((.+)\n*))+)$', '', data)        
+
+        data = re.sub('<(((?!>).)*)>', ' ', data)
+        data = re.sub('\n', ' ', data)
+        data = re.sub('^ +', '', data)
+        data = re.sub(' +$', '', data)
+        data = re.sub(' {2,}', ' ', data)
+    
+        return data[0:100] + '...'
+    else:
+        return ''
 
 def wiki_set(num = 1):
     if num == 1:
@@ -451,7 +530,7 @@ def wiki_set(num = 1):
         if db_data and db_data[0][0] != '':
             data_list += [db_data[0][0]]
         else:
-            data_list += ['CC 0']
+            data_list += ['ARR']
 
         data_list += ['', '']
 
@@ -497,55 +576,6 @@ def wiki_set(num = 1):
     else:
         return var_data
 
-def diff(seqm):
-    output = []
-
-    for opcode, a0, a1, b0, b1 in seqm.get_opcodes():
-        if opcode == 'equal':
-            output += [html.escape(seqm.a[a0:a1])]
-        elif opcode == 'insert':
-            output += ["<span style='background:#CFC;'>" + html.escape(seqm.b[b0:b1]) + "</span>"]
-        elif opcode == 'delete':
-            output += ["<span style='background:#FDD;'>" + html.escape(seqm.a[a0:a1]) + "</span>"]
-        elif opcode == 'replace':
-            output += ["<span style='background:#FDD;'>" + html.escape(seqm.a[a0:a1]) + "</span>"]
-            output += ["<span style='background:#CFC;'>" + html.escape(seqm.b[b0:b1]) + "</span>"]
-
-    end = ''.join(output)
-    end = end.replace('\r\n', '\n')
-    sub = ''
-
-    if not re.search('\n$', end):
-        end += '\n'
-
-    num = 0
-    left = 1
-    while 1:
-        data = re.search('((?:(?!\n).)*)\n', end)
-        if data:
-            data = data.groups()[0]
-
-            left += 1
-            if re.search('<span style=\'(?:(?:(?!\').)+)\'>', data):
-                num += 1
-                if re.search('<\/span>', data):
-                    num -= 1
-
-                sub += str(left) + ' : ' + re.sub('(?P<in>(?:(?!\n).)*)\n', '\g<in>', data, 1) + '<br>'
-            else:
-                if re.search('<\/span>', data):
-                    num -= 1
-                    sub += str(left) + ' : ' + re.sub('(?P<in>(?:(?!\n).)*)\n', '\g<in>', data, 1) + '<br>'
-                else:
-                    if num > 0:
-                        sub += str(left) + ' : ' + re.sub('(?P<in>.*)\n', '\g<in>', data, 1) + '<br>'
-
-            end = re.sub('((?:(?!\n).)*)\n', '', end, 1)
-        else:
-            break
-
-    return sub
-
 def admin_check(num = None, what = None, name = ''):
     if name == '':
         ip = ip_check()
@@ -1015,12 +1045,8 @@ def history_plus(title, data, date, ip, send, leng, t_check = '', d_type = ''):
             ])
 
     send = re.sub('\(|\)|<|>', '', send)
-
-    if len(send) > 128:
-        send = send[:128]
-
-    if t_check != '':
-        send += ' (' + t_check + ')'
+    send = send[:128] if len(send) > 128 else send
+    send = send + ' (' + t_check + ')' if t_check != '' else send
 
     curs.execute(db_change("insert into history (id, title, data, date, ip, send, leng, hide, type) values (?, ?, ?, ?, ?, ?, ?, '', ?)"), [
         id_data,
@@ -1139,6 +1165,10 @@ def re_error(data):
                 data = load_lang('fast_edit_error') + slow_data[0][0]
             elif num == 25:
                 data = load_lang('too_many_dec_error')
+            elif num == 26:
+                data = load_lang('application_not_found')
+            elif num == 27:
+                data = load_lang("invalid_password_error")
             else:
                 data = '???'
 

+ 1 - 1
route/tool/init.py

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

+ 22 - 33
route/tool/mark.py

@@ -1,13 +1,13 @@
-from .set_mark.namumark import namumark
-from .set_mark.markdown import markdown
+from .set_mark.namumark import namumark, link_fix
 
 from .set_mark.tool import *
 
 import re
 import html
 import sqlite3
-import urllib.parse
+import asyncio
 import threading
+import urllib.parse
 import multiprocessing
 
 def load_conn2(data):
@@ -36,47 +36,36 @@ def send_parser(data):
 
     return data
 
-def plusing(data):
-    for data_in in data:
-        curs.execute(db_change("select title from back where title = ? and link = ? and type = ?"), [data_in[1], data_in[0], data_in[2]])
-        if not curs.fetchall():
-            curs.execute(db_change("insert into back (title, link, type) values (?, ?, ?)"), [data_in[1], data_in[0], data_in[2]])
-
 def render_do(title, data, num, include):
+    if num == 3:
+        num = 1
+        back_num = 3
+    else:
+        back_num = num
+
     curs.execute(db_change('select data from other where name = "markup"'))
     rep_data = curs.fetchall()
     if rep_data[0][0] == 'namumark':
         data = namumark(conn, data, title, num, include)
-    elif rep_data[0][0] == 'js_namumark':
-        data = [
-            '<div id="render_contect">' + html.escape(data) + '</div>',
-            '<script>render_namumark("render_contect")</script>',
-            []
-        ]
-    elif rep_data[0][0] == 'markdown':
-        data = markdown(conn, data, title, num)
     elif rep_data[0][0] == 'raw':
         data = [data, '', []]
     else:
         data = ['', '', []]
 
     if num == 1:
-        data_num = len(data[2])
-        data_in_num = int(data_num / multiprocessing.cpu_count())
-        data_in = []
-
-        for i in range(multiprocessing.cpu_count()):
-            if i != multiprocessing.cpu_count() - 1:
-                data_in += [data[2][data_in_num * i:data_in_num * (i + 1)]]
-            else:
-                data_in += [data[2][data_in_num * i:]]
-
-        for data_in_for in data_in:
-            thread_start = threading.Thread(target = plusing, args = [data_in_for])
-            thread_start.start()
-            thread_start.join()
-
-        conn.commit()
+        if data[2] == []:
+            curs.execute(db_change("insert into back (title, link, type) values ('test', ?, 'nothing')"), [title])
+        else:
+            for data_in in data[2]:
+                try:
+                    curs.execute(db_change("insert into back (title, link, type) values (?, ?, ?)"), [data_in[1], data_in[0], data_in[2]])
+                except:
+                    pass
+
+                curs.execute(db_change("delete from back where title = ? and type = 'no'"), [title])
+
+        if back_num != 3:
+            conn.commit()
 
     if num == 2:
         return [data[0], data[1]]

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

@@ -1,14 +0,0 @@
-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]

+ 250 - 286
route/tool/set_mark/namumark.py

@@ -4,130 +4,36 @@ import datetime
 import html
 import re
 
-def table_parser(data, cel_data, start_data, num = 0):
-    table_class = 'class="'
-    div_style = 'style="'
-    all_table = 'style="'
-    cel_style = 'style="'
-    row_style = 'style="'
-    row = ''
-    cel = ''
+def link_fix(main_link):
+    if re.search('^:', main_link):
+        main_link = re.sub('^:', '', main_link)
 
-    table_width = re.search("&lt;table ?width=((?:(?!&gt;).)*)&gt;", data)
-    if table_width:
-        if re.search('^[0-9]+$', table_width.groups()[0]):
-            div_style += 'width: ' + table_width.groups()[0] + 'px;'
-        else:
-            div_style += 'width: ' + table_width.groups()[0] + ';'
-
-        all_table += 'width: 100%;'
-
-    table_height = re.search("&lt;table ?height=((?:(?!&gt;).)*)&gt;", data)
-    if table_height:
-        if re.search('^[0-9]+$', table_height.groups()[0]):
-            all_table += 'height: ' + table_height.groups()[0] + 'px;'
-        else:
-            all_table += 'height: ' + table_height.groups()[0] + ';'
-
-    # width, height
-
-    table_align = re.search("&lt;table ?align=((?:(?!&gt;).)*)&gt;", data)
-    if table_align:
-        if table_align.groups()[0] == 'right':
-            all_table += 'float: right;'
-        elif table_align.groups()[0] == 'center':
-            all_table += 'margin: auto;'
-
-    table_text_align = re.search("&lt;table ?textalign=((?:(?!&gt;).)*)&gt;", data)
-    if table_text_align:
-        num = 1
-
-        if table_text_align.groups()[0] == 'right':
-            all_table += 'text-align: right;'
-        elif table_text_align.groups()[0] == 'center':
-            all_table += 'text-align: center;'
-
-    row_table_align = re.search("&lt;row ?textalign=((?:(?!&gt;).)*)&gt;", data)
-    if row_table_align:
-        if row_table_align.groups()[0] == 'right':
-            row_style += 'text-align: right;'
-        elif row_table_align.groups()[0] == 'center':
-            row_style += 'text-align: center;'
-        else:
-            row_style += 'text-align: left;'
+    main_link = re.sub('^사용자:', 'user:', main_link)
+    main_link = re.sub('^파일:', 'file:', main_link)
+    main_link = re.sub('^분류:', 'category:', main_link)
 
-    # align
+    other_link = re.search('[^\\\\]?(#[^#]+)$', main_link)
+    if other_link:
+        other_link = other_link.groups()[0]
 
-    table_cel = re.search("&lt;-((?:(?!&gt;).)*)&gt;", data)
-    if table_cel:
-        cel = 'colspan="' + table_cel.groups()[0] + '"'
+        main_link = re.sub('(#[^#]+)$', '', main_link)
     else:
-        cel = 'colspan="' + str(round(len(start_data) / 2)) + '"'
-
-    table_row = re.search("&lt;\|((?:(?!&gt;).)*)&gt;", data)
-    if table_row:
-        row = 'rowspan="' + table_row.groups()[0] + '"'
+        other_link = ''
 
-    # <>
+    main_link = re.sub('\\\\#', '%23', main_link)
 
-    row_bgcolor = re.search("&lt;rowbgcolor=(#(?:[0-9a-f-A-F]{3}){1,2}|\w+)&gt;", data)
-    if row_bgcolor:
-        row_style += 'background: ' + row_bgcolor.groups()[0] + ';'
+    return [main_link, other_link]
 
-    row_bgcolor = re.search("&lt;rowcolor=(#(?:[0-9a-f-A-F]{3}){1,2}|\w+)&gt;", data)
-    if row_bgcolor:
-        row_style += 'color: ' + row_bgcolor.groups()[0] + ';'
-
-    # row
-
-    table_border = re.search("&lt;table ?bordercolor=(#(?:[0-9a-f-A-F]{3}){1,2}|\w+)&gt;", data)
-    if table_border:
-        all_table += 'border: ' + table_border.groups()[0] + ' 2px solid;'
-
-    table_bgcolor = re.search("&lt;table ?bgcolor=(#(?:[0-9a-f-A-F]{3}){1,2}|\w+)&gt;", data)
-    if table_bgcolor:
-        all_table += 'background: ' + table_bgcolor.groups()[0] + ';'
-
-    table_bgcolor = re.search("&lt;table ?color=(#(?:[0-9a-f-A-F]{3}){1,2}|\w+)&gt;", data)
-    if table_bgcolor:
-        all_table += 'color: ' + table_bgcolor.groups()[0] + ';'
-
-    # all
-
-    bgcolor = re.search("&lt;(?:bgcolor=)?(#(?:[0-9a-f-A-F]{3}){1,2}|\w+)&gt;", data)
-    if bgcolor:
-        cel_style += 'background: ' + bgcolor.groups()[0] + ';'
-
-    bgcolor = re.search("&lt;color=(#(?:[0-9a-f-A-F]{3}){1,2}|\w+)&gt;", data)
-    if bgcolor:
-        cel_style += 'color: ' + bgcolor.groups()[0] + ';'
-
-    cel_width = re.search("&lt;width=((?:(?!&gt;).)*)&gt;", data)
-    if cel_width:
-        if re.search('^[0-9]+$', cel_width.groups()[0]):
-            cel_style += 'width: ' + cel_width.groups()[0] + 'px;'
-        else:
-            cel_style += 'width: ' + cel_width.groups()[0] + ';'
+def table_parser(data, cel_data, start_data, num = 0):
+    table_class = 'class="'
+    div_style = 'style="'
+    all_table = 'style="'
+    cel_style = 'style="'
+    row_style = 'style="'
+    row = ''
+    cel = 'colspan="' + str(round(len(start_data) / 2)) + '"'
 
-    cel_height = re.search("&lt;height=((?:(?!&gt;).)*)&gt;", data)
-    if cel_height:
-        if re.search('^[0-9]+$', cel_height.groups()[0]):
-            cel_style += 'height: ' + cel_height.groups()[0] + 'px;'
-        else:
-            cel_style += 'height: ' + cel_height.groups()[0] + ';'
-
-    # cel
-
-    text_right = re.search("&lt;\)&gt;", data)
-    text_center = re.search("&lt;:&gt;", data)
-    text_left = re.search("&lt;\(&gt;",  data)
-    if text_right:
-        cel_style += 'text-align: right;'
-    elif text_center:
-        cel_style += 'text-align: center;'
-    elif text_left:
-        cel_style += 'text-align: left;'
-    elif num == 0:
+    if num == 0:
         if re.search('^ ', cel_data) and re.search(' $', cel_data):
             cel_style += 'text-align: center;'
         elif re.search('^ ', cel_data):
@@ -135,9 +41,80 @@ def table_parser(data, cel_data, start_data, num = 0):
         elif re.search(' $', cel_data):
             cel_style += 'text-align: left;'
 
-    text_class = re.search("&lt;table ?class=((?:(?!&gt;).)+)&gt;", data)
-    if text_class:
-        table_class += text_class.groups()[0]
+    table_state = re.findall('&lt;((?:(?!&gt;).)+)&gt;', data)
+    for in_state in table_state:
+        if re.search("^table ?width=([^=]+)$", in_state):
+            table_data = re.sub('^table ?width=', '', in_state)
+            div_style += 'width: ' + ((table_data + 'px') if re.search('^[0-9]+$', table_data) else table_data) + ';'
+            all_table += 'width: 100%;'
+        elif re.search("^table ?height=([^=]+)$", in_state):
+            table_data = re.sub('^table ?height=', '', in_state)
+            div_style += 'height: ' + ((table_data + 'px') if re.search('^[0-9]+$', table_data) else table_data) + ';'
+        elif re.search("^table ?align=([^=]+)$", in_state):
+            table_data = re.sub('^table ?align=', '', in_state)
+            if table_data == 'right':
+                div_style += 'float: right;'
+            elif table_data == 'center':
+                all_table += 'margin: auto;'
+        elif re.search("^table ?textalign=([^=]+)$", in_state):
+            num = 1
+            table_data = re.sub('^table ?textalign=', '', in_state)
+            if table_data == 'right':
+                all_table += 'text-align: right;'
+            elif table_data == 'center':
+                all_table += 'text-align: center;'
+        elif re.search("^row ?textalign=([^=]+)$", in_state):
+            table_data = re.sub('^row ?textalign=', '', in_state)
+            if table_data == 'right':
+                row_style += 'text-align: right;'
+            elif table_data == 'center':
+                row_style += 'text-align: center;'
+            else:
+                row_style += 'text-align: left;'
+        elif re.search('^-([0-9]+)$', in_state):
+            cel = 'colspan="' + re.sub('^-', '', in_state) + '"'
+        elif re.search("^(\^|v)?\|([^|]+)$", in_state):
+            if re.search('^\^', in_state):
+                cel_style += 'vertical-align: top;'
+            elif re.search('^v', in_state):
+                cel_style += 'vertical-align: bottom;'
+
+            row = 'rowspan="' + re.sub('^(\^|v)?\|', '', in_state) + '"'
+        elif re.search("^row ?bgcolor=([^=]+)$", in_state):
+            table_data = re.sub('^row ?bgcolor=', '', in_state)
+            row_style += 'background: ' + re.sub(',([^,]*)', '', table_data) if re.search(',', table_data) else table_data + ';'
+        elif re.search("^row ?color=([^=]+)$", in_state):
+            table_data = re.sub('^row ?color=', '', in_state)
+            row_style += 'color: ' + re.sub(',([^,]*)', '', table_data) if re.search(',', table_data) else table_data + ';'
+        elif re.search("^table ?bordercolor=([^=]+)$", in_state):
+            table_data = re.sub('^table ?bordercolor=', '', in_state)
+            all_table += 'border: ' + re.sub(',([^,]*)', '', table_data) if re.search(',', table_data) else table_data + ' 2px solid;'
+        elif re.search("^table ?bgcolor=([^=]+)$", in_state):
+            table_data = re.sub('^table ?bgcolor=', '', in_state)
+            all_table += 'background: ' + re.sub(',([^,]*)', '', table_data) if re.search(',', table_data) else table_data + ';'
+        elif re.search("^table ?color=([^=]+)$", in_state):
+            table_data = re.sub('^table ?color=', '', in_state)
+            all_table += 'color: ' + re.sub(',([^,]*)', '', table_data) if re.search(',', table_data) else table_data + ';'
+        elif re.search("^(bgcolor=([^=]+)|#(?:[0-9a-f-A-F]{3}){1,2}|\w+)$", in_state):
+            cel_style += 'background: ' + re.sub('^bgcolor=', '', in_state) + ';'
+        elif re.search("^color=([^=]+)$", in_state):
+            table_data = re.sub('^color=', '', in_state)
+            cel_style += 'color: ' + re.sub(',([^,]*)', '', table_data) if re.search(',', table_data) else table_data + ';'
+        elif re.search("^width=([^=]+)$", in_state):
+            table_data = re.sub('^width=', '', in_state)
+            cel_style += 'width: ' + ((table_data + 'px') if re.search('^[0-9]+$', table_data) else table_data) + ';'
+        elif re.search("^height=([^=]+)$", in_state):
+            table_data = re.sub('^height=', '', in_state)
+            cel_style += 'height: ' + ((table_data + 'px') if re.search('^[0-9]+$', table_data) else table_data) + ';'
+        elif re.search('^\(|:|\)$', in_state):
+            if in_state == '(':
+                cel_style += 'text-align: right;'
+            elif in_state == ':':
+                cel_style += 'text-align: center;'
+            else:
+                cel_style += 'text-align: left;'
+        elif re.search("^table ?class=([^=]+)$", in_state):
+            table_class += re.sub("^table ?class=", '', in_state)
 
     div_style += '"'
     all_table += '"'
@@ -149,30 +126,32 @@ def table_parser(data, cel_data, start_data, num = 0):
 
 def table_start(data):
     while 1:
-        table = re.search('\n((?:(?:(?:(?:\|\|)+(?:(?:(?!\|\|).(?:\n)*)*))+)\|\|(?:\n)?)+)', data)
+        table = re.search('\n((?:(?:(?:(?:\|\||\|[^|]+\|)+(?:(?:(?!\|\|).\n*)*))+)\|\|(?:\n)?)+)', data)
         if table:
             table = table.groups()[0]
-            while 1:
-                all_table = re.search('^((?:\|\|)+)((?:&lt;(?:(?:(?!&gt;).)+)&gt;)*)\n*((?:(?!\|\|).\n*)*)', table)
-                if all_table:
-                    all_table = all_table.groups()
 
-                    return_table = table_parser(all_table[1], all_table[2], all_table[0])
-                    number = return_table[6]
-
-                    table = re.sub(
-                        '^((?:\|\|)+)((?:&lt;(?:(?:(?!&gt;).)+)&gt;)*)\n*',
-                        '\n' + \
-                            '<div class="table_safe" ' + return_table[7] + '>' + \
-                                '<table ' + return_table[5] + ' ' + return_table[0] + '>' + \
-                                    '<tbody>' + \
-                                        '<tr ' + return_table[1] + '>' + \
-                                            '<td ' + return_table[2] + ' ' + return_table[3] + ' ' + return_table[4] + '>',
-                        table,
-                        1
-                    )
-                else:
-                    break
+            all_table = re.search('^((?:\|\||\|[^|]+\|)+)((?:&lt;(?:(?:(?!&gt;).)+)&gt;)*)\n*((?:(?!\|\|).\n*)*)', table)
+            if all_table:
+                all_table = all_table.groups()
+
+                return_table = table_parser(all_table[1], all_table[2], re.sub('^\|([^|]+)\|', '||', all_table[0]))
+                number = return_table[6]
+
+                table_caption = re.search('^\|([^|]+)\|', table)
+                table_caption = '<caption>' + table_caption.groups()[0] + '</caption>' if table_caption else ''
+
+                table = re.sub(
+                    '^((?:\|\||\|[^|]+\|)+)((?:&lt;(?:(?:(?!&gt;).)+)&gt;)*)\n*',
+                    '\n' + \
+                        '<div class="table_safe" ' + return_table[7] + '>' + \
+                            '<table ' + return_table[5] + ' ' + return_table[0] + '>' + \
+                                table_caption + \
+                                '<tbody>' + \
+                                    '<tr ' + return_table[1] + '>' + \
+                                        '<td ' + return_table[2] + ' ' + return_table[3] + ' ' + return_table[4] + '>',
+                    table,
+                    1
+                )
 
             table = re.sub('\|\|\n?$', '</td></tr></tbody></table></div>', table)
 
@@ -208,20 +187,23 @@ def table_start(data):
                 else:
                     break
 
-            data = re.sub('\n((?:(?:(?:(?:\|\|)+(?:(?:(?!\|\|).(?:\n)*)*))+)\|\|(?:\n)?)+)', table, data, 1)
+            data = re.sub('\n((?:(?:(?:(?:\|\||\|[^|]+\|)+(?:(?:(?!\|\|).\n*)*))+)\|\|(?:\n)?)+)', table, data, 1)
         else:
             break
 
     return data
 
-def middle_parser(data, fol_num, syntax_num, folding_num, include_num):
+def middle_parser(data, include_num):
     global end_data
     global plus_data
 
     middle_stack = 0
     middle_list = []
-    middle_number = 0
-    html_number = 0
+    middle_num = 0
+
+    html_num = 0
+    syntax_num = 0
+    folding_num = 0
 
     middle_re = re.compile('(?:{{{((?:(?:(?! |{{{|}}}|&lt;).)*) ?)|(}}}))')
     middle_all_data = middle_re.findall(data)
@@ -287,7 +269,7 @@ def middle_parser(data, fol_num, syntax_num, folding_num, include_num):
                             middle_data_2 = ['python']
 
                         if syntax_num == 0:
-                            plus_data += '<script>hljs.initHighlightingOnLoad();</script>'
+                            plus_data += 'hljs.initHighlightingOnLoad();\n'
 
                             syntax_num = 1
 
@@ -308,31 +290,28 @@ def middle_parser(data, fol_num, syntax_num, folding_num, include_num):
                         else:
                             folding_data = ['Test']
 
-                        if folding_num == 0:
-                            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="do_open_folding(\'' + include_num + 'folding_' + str(fol_num) + '\', this);">' + \
+                                    '<a href="javascript:void(0);" onclick="do_open_folding(\'' + include_num + 'folding_' + str(folding_num) + '\', this);">' + \
                                         '[+]' + \
                                     '</a>' + \
                                 '</div_2>' + \
-                                '<div id="' + include_num + 'folding_' + str(fol_num) + '" style="display: none;">' + \
+                                '<div id="' + include_num + 'folding_' + str(folding_num) + '" style="display: none;">' + \
                                     '<div id="wiki_div" style="">',
                             data,
                             1
                         )
 
-                        fol_num += 1
+                        folding_num += 1
                     elif re.search('^#!html', middle_data[0]):
                         middle_list += ['span']
 
-                        html_number += 1
+                        html_num += 1
 
-                        data = middle_re.sub('<span id="' + include_num + 'render_contect_' + str(html_number) + '">', data, 1)
+                        data = middle_re.sub('<span id="' + include_num + 'render_contect_' + str(html_num) + '">', data, 1)
                     else:
                         middle_list += ['span']
 
@@ -344,7 +323,7 @@ def middle_parser(data, fol_num, syntax_num, folding_num, include_num):
 
                     data = middle_re.sub('<code>' + middle_data[0].replace('\\', '\\\\'), data, 1)
 
-                middle_number += 1
+                middle_num += 1
         else:
             if middle_list == []:
                 data = middle_re.sub('&#125;&#125;&#125;', data, 1)
@@ -355,17 +334,17 @@ def middle_parser(data, fol_num, syntax_num, folding_num, include_num):
                 if middle_stack > 0:
                     data = middle_re.sub('&#125;&#125;&#125;', data, 1)
                 else:
-                    if middle_number > 0:
-                        middle_number -= 1
+                    if middle_num > 0:
+                        middle_num -= 1
 
-                    if middle_list[middle_number] == '2div':
+                    if middle_list[middle_num] == '2div':
                         data = middle_re.sub('</div_1></div_2></div_2>', data, 1)
-                    elif middle_list[middle_number] == 'pre':
+                    elif middle_list[middle_num] == 'pre':
                         data = middle_re.sub('</code></pre>', data, 1)
                     else:
-                        data = middle_re.sub('</' + middle_list[middle_number] + '>', data, 1)
+                        data = middle_re.sub('</' + middle_list[middle_num] + '>', data, 1)
 
-                    del(middle_list[middle_number])
+                    del(middle_list[middle_num])
 
     while 1:
         if middle_stack == 0:
@@ -380,17 +359,17 @@ def middle_parser(data, fol_num, syntax_num, folding_num, include_num):
                 if middle_stack > 0:
                     data += '&#125;&#125;&#125;'
                 else:
-                    if middle_number > 0:
-                        middle_number -= 1
+                    if middle_num > 0:
+                        middle_num -= 1
 
-                    if middle_list[middle_number] == '2div':
+                    if middle_list[middle_num] == '2div':
                         data += '</div_1></div_2></div_2>'
-                    elif middle_list[middle_number] == 'pre':
+                    elif middle_list[middle_num] == 'pre':
                         data += '</code></pre>'
                     else:
-                        data += '</' + middle_list[middle_number] + '>'
+                        data += '</' + middle_list[middle_num] + '>'
 
-                    del(middle_list[middle_number])
+                    del(middle_list[middle_num])
 
     num = 0
     while 1:
@@ -399,8 +378,7 @@ def middle_parser(data, fol_num, syntax_num, folding_num, include_num):
             nowiki_data = nowiki_data.groups()
 
             num += 1
-
-            end_data += [['nowiki_' + str(num), nowiki_data[0], 'code']]
+            end_data['nowiki_' + str(num)] = [nowiki_data[0], 'code']
 
             data = re.sub(
                 '<code>((?:(?:(?!<\/code>).)*\n*)*)<\/code>',
@@ -413,16 +391,16 @@ def middle_parser(data, fol_num, syntax_num, folding_num, include_num):
 
     num = 0
     while 1:
-        syntax_data = re.search('<code class="((?:(?!").)+)">((?:(?:(?:(?!<\/code>|<span id="syntax_)).)+\n*)+)<\/code>', data)
+        syntax_data = re.search('<code class="((?:(?!"|>|<).)+)">((?:\n*(?:(?:(?!<\/code>|<span id="syntax_).)+)\n*)+)<\/code>', data)
         if syntax_data:
             syntax_data = syntax_data.groups()
 
             num += 1
 
-            end_data += [['syntax_' + str(num), syntax_data[1], 'normal']]
+            end_data['syntax_' + str(num)] = [syntax_data[1], 'normal']
 
             data = re.sub(
-                '<code class="((?:(?!").)+)">((?:(?:(?:(?!<\/code>|<span id="syntax_)).)+\n*)+)<\/code>',
+                '<code class="((?:(?!"|>|<).)+)">((?:\n*(?:(?:(?!<\/code>|<span id="syntax_).)+)\n*)+)<\/code>',
                 '<code class="' + syntax_data[0] + '"><span id="syntax_' + str(num) + '"></span></code>',
                 data,
                 1
@@ -430,7 +408,7 @@ def middle_parser(data, fol_num, syntax_num, folding_num, include_num):
         else:
             break
 
-    return [data, [fol_num, syntax_num, folding_num]]
+    return data
 
 def namumark(conn, data, title, main_num, include_num):
     curs = conn.cursor()
@@ -439,12 +417,11 @@ def namumark(conn, data, title, main_num, include_num):
     global end_data
 
     data = '\n' + data + '\n'
-    plus_data = ''
+    include_num = include_num + '_' if include_num else ''
+    plus_data = 'get_link_state("' + include_num + '");\nget_file_state("' + include_num + '");\n'
 
     backlink = []
-    end_data = []
-
-    include_num = include_num + '_' if include_num else ''
+    end_data = {}
 
     data = re.sub('<math>(?P<in>(?:(?!<\/math>).)+)<\/math>', '[math(\g<in>)]', data)
 
@@ -463,22 +440,20 @@ def namumark(conn, data, title, main_num, include_num):
             data = math_re.sub('<span id="math_' + str(first) + '"></span>', data, 1)
 
             plus_data += '''
-                <script>
-                    try {
-                        katex.render(
-                            "''' + html.unescape(math).replace('\\', '\\\\').replace('"', '\\"') + '''",
-                            document.getElementById("math_''' + str(first) + '''")
-                        );
-                    } catch {
-                        document.getElementById("math_''' + str(first) + '''").innerHTML = '<span style="color: red;">''' + math.replace('\\', '\\\\') + '''</span>';
-                    }
-                </script>
+                try {
+                    katex.render(
+                        "''' + html.unescape(math).replace('\\', '\\\\').replace('"', '\\"') + '''",
+                        document.getElementById("math_''' + str(first) + '''")
+                    );
+                } catch {
+                    document.getElementById("math_''' + str(first) + '''").innerHTML = '<span style="color: red;">''' + math.replace('\\', '\\\\') + '''</span>';
+                }\n
             '''
         else:
             break
 
     data = re.sub('\\\\{', '<break_middle>', data)
-    data = middle_parser(data, 0, 0, 0, include_num)[0]
+    data = middle_parser(data, include_num)
     data = re.sub('<break_middle>', '\\{', data)
 
     num = 0
@@ -489,7 +464,7 @@ def namumark(conn, data, title, main_num, include_num):
 
             num += 1
 
-            end_data += [['one_nowiki_' + str(num), one_nowiki[0], 'normal']]
+            end_data['one_nowiki_' + str(num)] = [one_nowiki[0], 'normal']
 
             data = re.sub('(?:\\\\)(.)', '<span id="one_nowiki_' + str(num) + '"></span>', data, 1)
         else:
@@ -511,29 +486,31 @@ def namumark(conn, data, title, main_num, include_num):
                 include_data = 'Test'
 
             include_link = include_data
-
             backlink += [[title, include_link, 'include']]
 
-            curs.execute(tool.db_change("select title from data where title = ?"), [include_data])
-            if curs.fetchall():
-                data = include_re.sub('' + \
-                    '<a id="include_link" href="/w/' + tool.url_pas(include_link) + '">[' + include_link + ']</a><div id="include_' + str(i) + '"></div>' + \
-                '', data, 1)
+            data = include_re.sub('' + \
+                '<a id="include_link" class="include_' + str(i) + '" href="/w/' + tool.url_pas(include_link) + '">[' + include_link + ']</a>' + \
+                '<div id="include_' + str(i) + '"></div>' + \
+            '', data, 1)
 
-                include_plus_data = []
-                while 1:
-                    include_plus = re.search(', ?((?:(?!=).)+)=((?:(?!,).)+)', include)
-                    if include_plus:
-                        include_plus = include_plus.groups()
-                        include_plus_data += [[include_plus[0], include_plus[1]]]
+            include_plus_data = []
+            while 1:
+                include_plus = re.search(', ?((?:(?!=).)+)=((?:(?!,).)+)', include)
+                if include_plus:
+                    include_plus = include_plus.groups()
 
-                        include = re.sub(', ?((?:(?!=).)+)=((?:(?!,).)+)', '', include, 1)
-                    else:
-                        break
+                    include_data_set = include_plus[1]
+                    find_data = re.findall('<span id="(one_nowiki_[0-9]+)">', include_data_set)
+                    for j in find_data:
+                        include_data_set = include_data_set.replace('<span id="' + j + '"></span>', end_data[j][0])
 
-                plus_data += '<script>load_include("' + include_link + '", "include_' + str(i) + '", ' + str(include_plus_data) + ');</script>'
-            else:
-                data = include_re.sub('<a id="not_thing" href="/w/' + tool.url_pas(include_link) + '">[' + include_link + ']</a>', data, 1)
+                    include_plus_data += [[include_plus[0], include_data_set]]
+
+                    include = re.sub(', ?((?:(?!=).)+)=((?:(?!,).)+)', '', include, 1)
+                else:
+                    break
+
+            plus_data += 'load_include("' + include_link + '", "include_' + str(i) + '", ' + str(include_plus_data) + ');\n'
         else:
             break
 
@@ -565,20 +542,12 @@ def namumark(conn, data, title, main_num, include_num):
     data += '\n'
     data = data.replace('\\', '&#92;')
 
-    data = re.sub('&#x27;&#x27;&#x27;(?P<in>((?!&#x27;&#x27;&#x27;).)+)&#x27;&#x27;&#x27;', '<b>\g<in></b>', data)
-    data = re.sub('&#x27;&#x27;(?P<in>((?!&#x27;&#x27;).)+)&#x27;&#x27;', '<i>\g<in></i>', data)
-    data = re.sub('~~(?P<in>(?:(?!~~).)+)~~', '<s>\g<in></s>', data)
-    data = re.sub('--(?P<in>(?:(?!--).)+)--', '<s>\g<in></s>', data)
-    data = re.sub('__(?P<in>(?:(?!__).)+)__', '<u>\g<in></u>', data)
-    data = re.sub('\^\^(?P<in>(?:(?!\^\^).)+)\^\^', '<sup>\g<in></sup>', data)
-    data = re.sub(',,(?P<in>(?:(?!,,).)+),,', '<sub>\g<in></sub>', data)
-
     redirect_re = re.compile('\n#(?:redirect|넘겨주기) ((?:(?!\n).)+)\n', re.I)
     redirect = redirect_re.search(data)
     if redirect:
         redirect = redirect.groups()[0]
 
-        return_link = tool.link_fix(redirect)
+        return_link = link_fix(redirect)
         main_link = return_link[0]
         other_link = return_link[1]
 
@@ -723,7 +692,6 @@ def namumark(conn, data, title, main_num, include_num):
 
         data = re.sub("\[ruby\(((?:(?:(?!\)\]).)+))\)\]", ruby_data, data, 1, flags = re.I)
 
-
     curs.execute(tool.db_change('select data from other where name = "count_all_title"'))
     all_title = curs.fetchall()
     data = re.sub('\[pagecount\]', all_title[0][0], data, flags = re.I)
@@ -740,12 +708,15 @@ def namumark(conn, data, title, main_num, include_num):
         if age_data:
             age = age_data.groups()[0]
 
-            old = datetime.datetime.strptime(time[0], '%Y-%m-%d')
-            will = datetime.datetime.strptime(age, '%Y-%m-%d')
+            try:
+                old = datetime.datetime.strptime(time[0], '%Y-%m-%d')
+                will = datetime.datetime.strptime(age, '%Y-%m-%d')
 
-            e_data = old - will
+                e_data = old - will
 
-            data = age_re.sub(str(int(e_data.days / 365)), data, 1)
+                data = age_re.sub(str(int(e_data.days / 365)), data, 1)
+            except:
+                data = age_re.sub('age-error', data, 1)
         else:
             break
 
@@ -755,17 +726,20 @@ def namumark(conn, data, title, main_num, include_num):
         if dday_data:
             dday = dday_data.groups()[0]
 
-            old = datetime.datetime.strptime(time[0], '%Y-%m-%d')
-            will = datetime.datetime.strptime(dday, '%Y-%m-%d')
+            try:
+                old = datetime.datetime.strptime(time[0], '%Y-%m-%d')
+                will = datetime.datetime.strptime(dday, '%Y-%m-%d')
 
-            e_data = old - will
+                e_data = old - will
 
-            if re.search('^-', str(e_data.days)):
-                e_day = str(e_data.days)
-            else:
-                e_day = '+' + str(e_data.days)
+                if re.search('^-', str(e_data.days)):
+                    e_day = str(e_data.days)
+                else:
+                    e_day = '+' + str(e_data.days)
 
-            data = dday_re.sub(e_day, data, 1)
+                data = dday_re.sub(e_day, data, 1)
+            except:
+                data = dday_re.sub('dday-error', data, 1)
         else:
             break
 
@@ -818,7 +792,11 @@ def namumark(conn, data, title, main_num, include_num):
             else:
                 video_src = 'https://embed.nicovideo.jp/watch/' + video_code
 
-            data = video_re.sub('<iframe style="width: ' + video_width + '; height: ' + video_height + ';" src="' + video_src + video_start + '" allowfullscreen></iframe>', data, 1)
+            data = video_re.sub(
+                '<iframe style="width: ' + video_width + '; height: ' + video_height + ';" src="' + video_src + video_start + '" allowfullscreen></iframe>', 
+                data, 
+                1
+            )
         else:
             break
 
@@ -882,7 +860,7 @@ def namumark(conn, data, title, main_num, include_num):
 
     data = table_start(data)
 
-    category = '<div id="cate_all"><hr><div id="cate">Category : '
+    category = ''
     category_re = re.compile('^(?:category|분류):', re.I)
     while 1:
         link = re.search('\[\[((?:(?!\[\[|\]\]).)+)\]\]', data)
@@ -954,9 +932,7 @@ def namumark(conn, data, title, main_num, include_num):
 
                     file_src = '/image/' + tool.sha224_replace(file_name) + '.' + file_end
                     file_alt = 'file:' + file_name + '.' + file_end
-
-                    curs.execute(tool.db_change("select title from data where title = ?"), [file_alt])
-                    exist = curs.fetchall()
+                    exist = None
 
                 if exist:
                     data = re.sub(
@@ -972,23 +948,30 @@ def namumark(conn, data, title, main_num, include_num):
                 else:
                     data = re.sub(
                         '\[\[((?:(?!\[\[|\]\]).)+)\]\]',
-                        '<a id="not_thing" href="/upload?name=' + tool.url_pas(file_name) + '">' + file_alt + '</a>',
+                        '<span style="' + file_align + '">' + \
+                            '<span style="' + file_color + '">' + \
+                                '<img class="' + include_num + 'file_finder_1" style="' + file_style + '" alt="' + file_alt + '" src="' + file_src + '">' + \
+                                '<a class="' + include_num + 'file_finder_2" id="not_thing" href="/upload?name=' + tool.url_pas(file_name) + '">' + file_alt + '</a>' + \
+                            '</span>' + \
+                        '</span>',
                         data,
                         1
                     )
             elif category_re.search(main_link):
+                if category == '':
+                    category += '<div id="cate_all"><hr><div id="cate">Category : '
+
                 main_link = category_re.sub('category:', main_link)
 
+                curs.execute(tool.db_change("select title from data where title = ?"), [main_link])
                 if re.search('#blur', main_link):
                     see_link = 'Hidden'
                     link_id = 'id="inside"'
 
                     main_link = re.sub('#blur', '', main_link)
-                else:
-                    link_id = ''
 
                 backlink += [[title, main_link, 'cat']]
-                category += '<a ' + link_id + ' href="' + tool.url_pas(main_link) + '">' + category_re.sub('', see_link) + '</a> | '
+                category += '<a class="' + include_num + 'link_finder" href="/w/' + tool.url_pas(main_link) + '">' + category_re.sub('', see_link) + '</a> | '
 
                 data = re.sub('\[\[((?:(?!\[\[|\]\]).)+)\]\]', '', data, 1)
             elif re.search('^wiki:', main_link):
@@ -1026,7 +1009,7 @@ def namumark(conn, data, title, main_num, include_num):
                         )
                 else:
                     data = re.sub('\[\[((?:(?!\[\[|\]\]).)+)\]\]', 'Not exist', data, 1)
-            elif re.search('^\/', main_link):
+            elif re.search('^(\/(?:.+))$', main_link):
                 under_title = re.search('^(\/(?:.+))$', main_link)
                 under_title = under_title.groups()[0]
 
@@ -1037,7 +1020,7 @@ def namumark(conn, data, title, main_num, include_num):
             elif re.search('^http(s)?:\/\/', main_link):
                 data = re.sub('\[\[((?:(?!\[\[|\]\]).)+)\]\]', '<a id="out_link" rel="nofollow" href="' + main_link + '">' + see_link + '</a>', data, 1)
             else:
-                return_link = tool.link_fix(main_link)
+                return_link = link_fix(main_link)
                 main_link = html.unescape(return_link[0])
                 other_link = return_link[1]
 
@@ -1051,19 +1034,15 @@ def namumark(conn, data, title, main_num, include_num):
                 if not re.search('^\|', main_link):
                     if main_link != title:
                         if main_link != '':
+                            backlink += [[title, main_link, '']]
+
                             curs.execute(tool.db_change("select title from data where title = ?"), [main_link])
                             if not curs.fetchall():
-                                link_id = 'id="not_thing"'
-
                                 backlink += [[title, main_link, 'no']]
-                            else:
-                                link_id = ''
-
-                            backlink += [[title, main_link, '']]
 
                             data = re.sub(
                                 '\[\[((?:(?!\[\[|\]\]).)+)\]\]',
-                                '<a ' + link_id + ' ' + \
+                                '<a class="' + include_num + 'link_finder" ' + \
                                     'title="' + main_link + other_link + '" ' + \
                                     'href="/w/' + tool.url_pas(main_link) + other_link + '"' + \
                                 '>' + see_link + '</a>',
@@ -1189,14 +1168,14 @@ def namumark(conn, data, title, main_num, include_num):
         if footdata[2] == 0:
             footdata_in = ''
         else:
-            footdata_in = footdata[2]
+            footdata_in = str(footdata[2])
 
         footdata_all += '' + \
             '<li>' + \
                 '<a href="#' + include_num + 'rfn-' + str(footdata[0]) + '" ' + \
                     'id="' + include_num + 'cfn-' + str(footdata[0]) + '" ' + \
                     'onclick="do_open_foot(\'' + include_num + 'fn-' + str(footdata[0]) + '\', 1);">' + \
-                    '(' + footdata[1] + ')' + \
+                    '(' + str(footdata[1]) + ')' + \
                 '</a> <span id="' + include_num + 'fn-' + str(footdata[0]) + '">' + footdata_in + '</span>' + \
             '</li>' + \
         ''
@@ -1208,31 +1187,28 @@ def namumark(conn, data, title, main_num, include_num):
 
     data = re.sub('\n$', footdata_all, data + '\n', 1)
 
-    category += '</div></div>'
-    category = re.sub(' \| <\/div><\/div>$', '</div></div>', category)
+    data = re.sub('&#x27;&#x27;&#x27;(?P<in>((?!&#x27;&#x27;&#x27;).)+)&#x27;&#x27;&#x27;', '<b>\g<in></b>', data)
+    data = re.sub('&#x27;&#x27;(?P<in>((?!&#x27;&#x27;).)+)&#x27;&#x27;', '<i>\g<in></i>', data)
+    data = re.sub('~~(?P<in>(?:(?!~~).)+)~~', '<s>\g<in></s>', data)
+    data = re.sub('--(?P<in>(?:(?!--).)+)--', '<s>\g<in></s>', data)
+    data = re.sub('__(?P<in>(?:(?!__).)+)__', '<u>\g<in></u>', data)
+    data = re.sub('\^\^(?P<in>(?:(?!\^\^).)+)\^\^', '<sup>\g<in></sup>', data)
+    data = re.sub(',,(?P<in>(?:(?!,,).)+),,', '<sub>\g<in></sub>', data)
 
-    if category == '<div id="cate_all"><hr><div id="cate">Category : </div></div>':
-        category = ''
+    if category != '':
+        category = re.sub(' \| $', '', category) + '</div></div>'
 
     data += category
 
-    i = 0
-    while 1:
-        try:
-            _ = end_data[i][0]
-        except:
-            break
-
-        if end_data[i][2] == 'normal':
-            data = data.replace('<span id="' + end_data[i][0] + '"></span>', end_data[i][1])
-            data = data.replace(tool.url_pas('<span id="' + end_data[i][0] + '"></span>'), tool.url_pas(end_data[i][1]))
+    for i in end_data:
+        if end_data[i][1] == 'normal':
+            data = data.replace('<span id="' + i + '"></span>', end_data[i][0])
+            data = data.replace(tool.url_pas('<span id="' + i + '"></span>'), tool.url_pas(end_data[i][0]))
         else:
-            if re.search('\n', end_data[i][1]):
-                data = data.replace('<span id="' + end_data[i][0] + '"></span>', '\n<pre>' + re.sub('^\n', '', end_data[i][1]) + '</pre>')
+            if re.search('\n', end_data[i][0]):
+                data = data.replace('<span id="' + i + '"></span>', '\n<pre>' + re.sub('^\n', '', end_data[i][0]) + '</pre>')
             else:
-                data = data.replace('<span id="' + end_data[i][0] + '"></span>', '<code>' + end_data[i][1] + '</code>')
-
-        i += 1
+                data = data.replace('<span id="' + i + '"></span>', '<code>' + end_data[i][0] + '</code>')
 
     if main_num == 1:
         i = 0
@@ -1242,24 +1218,12 @@ def namumark(conn, data, title, main_num, include_num):
             except:
                 break
 
-            find_data = re.search('<span id="(one_nowiki_[0-9]+)">', backlink[i][1])
-            if find_data:
-                j = 0
-                find_data = find_data.groups()[0]
-
-                while 1:
-                    try:
-                        _ = end_data[j][0]
-                    except:
-                        break
-
-                    if end_data[j][0] == find_data:
-                        if backlink[i][2] != 'redirect':
-                            backlink[i][1] = backlink[i][1].replace('<span id="' + end_data[j][0] + '"></span>', end_data[j][1])
-                        else:
-                            backlink[i][1] = backlink[i][1].replace('<span id="' + end_data[j][0] + '"></span>', '\\' + end_data[j][1])
-
-                    j += 1
+            find_data = re.findall('<span id="(one_nowiki_[0-9]+)">', backlink[i][1])
+            for j in find_data:
+                if backlink[i][2] != 'redirect':
+                    backlink[i][1] = backlink[i][1].replace('<span id="' + j + '"></span>', end_data[j][0])
+                else:
+                    backlink[i][1] = backlink[i][1].replace('<span id="' + j + '"></span>', '\\' + end_data[j][0])
 
             i += 1
 
@@ -1278,6 +1242,6 @@ def namumark(conn, data, title, main_num, include_num):
     data = re.sub('\n<\/ul>', '</ul>', data)
     data = re.sub('\n', '<br>', data)
 
-    plus_data = '<script>render_html("' + include_num + 'render_contect");</script>' + plus_data
+    plus_data = 'render_html("' + include_num + 'render_contect");\n' + plus_data
 
     return [data, plus_data, backlink]

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


+ 9 - 25
route/tool/set_mark/tool.py

@@ -9,7 +9,6 @@ def get_time():
 
 def db_data_get(data):
     global set_data
-
     set_data = data
 
 def db_change(data):
@@ -26,38 +25,23 @@ def ip_check(d_type = 0):
         ip = flask.session['id']
     
     if ip == '':
-        ip = flask.request.environ.get('HTTP_X_REAL_IP', flask.request.environ.get('HTTP_X_FORWARDED_FOR', flask.request.remote_addr))
+        try:
+            ip = flask.request.environ.get('HTTP_X_REAL_IP', flask.request.environ.get('HTTP_X_FORWARDED_FOR', flask.request.remote_addr))
+            ip = ip[0] if type(ip) == type([]) else ip
 
-        if ip == '::1' or ip == '127.0.0.1':
-            ip = flask.request.environ.get('HTTP_X_FORWARDED_FOR', flask.request.remote_addr)
+            if ip == '::1' or ip == '127.0.0.1':
+                ip = flask.request.environ.get('HTTP_X_FORWARDED_FOR', flask.request.remote_addr)
+                ip = ip[0] if type(ip) == type([]) else ip
+        except:
+            ip = 'error: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 = ''
-
-    main_link = re.sub('\\\\#', '%23', main_link)
-
-    return [main_link, other_link]
-
 def savemark(data):
     data = re.sub("\[date\(now\)\]", get_time(), data)
 
     ip = ip_check()
-    if not re.search("\.", ip):
+    if not re.search("\.|:", ip):
         name = '[[user:' + ip + '|' + ip + ']]'
     else:
         name = ip

+ 1 - 1
route/topic.py

@@ -92,7 +92,7 @@ def topic_2(conn, topic_num):
         ])
         conn.commit()
 
-        return redirect('/thread/' + str(topic_num))
+        return redirect('/thread/' + str(topic_num) + '?where=bottom')
     else:
         data = ''
 

+ 1 - 1
route/user_custom_head_view.py

@@ -17,7 +17,7 @@ def user_custom_head_view_2(conn):
 
         flask.session['head'] = flask.request.form.get('content', None)
 
-        return redirect('/user')
+        return redirect('/custom_head')
     else:
         if ip_or_user(ip) == 0:
             start = ''

+ 24 - 2
route/view_diff_data.py

@@ -21,9 +21,31 @@ def view_diff_data_2(conn, name):
         if second_raw_data:
             if first == second:
                 result = ''
+            elif first_raw_data == second_raw_data:
+                result = ''
             else:
-                diff_data = difflib.SequenceMatcher(None, first_raw_data[0][0], second_raw_data[0][0])
-                result = '<pre>' + diff(diff_data) + '</pre>'
+                i = 2
+                include_ins = 0
+                diff_data = '1 : ' + diff_match_patch().diff_prettyHtml(diff_match_patch().diff_main(first_raw_data[0][0], second_raw_data[0][0]))
+
+                re_data = re.findall('((?:(?!&para;<br>).)*)(?:&para;<br>|$)', diff_data)
+                for re_in_data in re_data:
+                    if re.search('(<ins |<del )', re_in_data) and re.search('(<\/ins>|<\/del>)', re_in_data):
+                        re_data[i - 2] = str(i) + ' : ' + re_data[i - 2] + '\n'
+                        include_ins = 0
+                    elif re.search('(<\/ins>|<\/del>)', re_in_data):
+                        re_data[i - 2] = str(i) + ' : ' + re_data[i - 2] + '\n'
+                        include_ins = 0
+                    elif re.search('(<ins |<del )', re_in_data) or include_ins == 1:
+                        re_data[i - 2] = str(i) + ' : ' + re_data[i - 2] + '\n'
+                        include_ins = 1
+                    else:
+                        re_data[i - 2] = ''
+                        include_ins = 0
+
+                    i += 1
+                    
+                result = '<pre>' + ''.join(re_data) + '</pre>'
 
             return easy_minify(flask.render_template(skin_check(),
                 imp = [name, wiki_set(), custom(), other2([' (' + load_lang('compare') + ')', 0])],

+ 42 - 19
route/view_read.py

@@ -18,7 +18,7 @@ def view_read_2(conn, name):
             if r_db:
                 r_data = link_fix(r_db[0][0])
 
-                return redirect('/w/' + r_data[0] + '?from=' + name + r_data[1])
+                return redirect('/w/' + url_pas(r_data[0]) + '?from=' + name + r_data[1])
 
     curs.execute(db_change("select sub from rd where title = ? and not stop = 'O' order by date desc"), [name])
     if curs.fetchall():
@@ -67,34 +67,51 @@ def view_read_2(conn, name):
                 div += '<br><h2 id="cate_under">' + load_lang('under_category') + '</h2><ul>' + u_div + '</ul>'
 
 
+    cache_data = None
     if num:
         curs.execute(db_change("select title from history where title = ? and id = ? and hide = 'O'"), [name, str(num)])
         if curs.fetchall() and admin_check(6) != 1:
             return redirect('/history/' + url_pas(name))
 
-        curs.execute(db_change("select title, data from history where title = ? and id = ?"), [name, str(num)])
+        curs.execute(db_change("select data from history where title = ? and id = ?"), [name, str(num)])
     else:
-        curs.execute(db_change("select title, data from data where title = ?"), [name])
+        curs.execute(db_change("select id from history where title = ? order by id + 0 desc limit 1"), [name])
+        last_history_num = curs.fetchall()
+        if last_history_num and not flask.request.args.get('reload', None):
+            curs.execute(db_change("select data from cache_data where title = ? and id = ?"), [name, last_history_num[0][0]])
+            cache_data = curs.fetchall()
+            if not cache_data:
+                curs.execute(db_change("select data from data where title = ?"), [name])
+        else:
+            curs.execute(db_change("select data from data where title = ?"), [name])
 
-    data = curs.fetchall()
-    if data:
-        else_data = data[0][1]
+    if cache_data:
+        end_data = cache_data[0][0]
     else:
-        else_data = None
+        data = curs.fetchall()
+        if data:
+            else_data = data[0][0]
+        else:
+            else_data = None
+
+        curs.execute(db_change("select decu from acl where title = ?"), [name])
+        data = curs.fetchall()
+        if data:
+            acl = 1
 
-    curs.execute(db_change("select decu from acl where title = ?"), [name])
-    data = curs.fetchall()
-    if data:
-        acl = 1
+        if flask.request.args.get('from', None) and else_data:
+            else_data = re.sub('^\r\n', '', else_data)
+            else_data = re.sub('\r\n$', '', else_data)
 
-    if flask.request.args.get('from', None) and else_data:
-        else_data = re.sub('^\r\n', '', else_data)
-        else_data = re.sub('\r\n$', '', else_data)
+        end_data = render_set(
+            title = name,
+            data = else_data
+        )
 
-    end_data = render_set(
-        title = name,
-        data = else_data
-    )
+        if not num:
+            curs.execute(db_change("delete from cache_data where title = ?"), [name])
+            if last_history_num:
+                curs.execute(db_change("insert into cache_data (title, data, id) values (?, ?, ?)"), [name, end_data, last_history_num[0][0]])
 
     if end_data == 'HTTP Request 401.3':
         response_data = 401
@@ -144,7 +161,13 @@ def view_read_2(conn, name):
         else:
             menu = [['edit/' + url_pas(name), load_lang('edit')]]
 
-        menu += [['topic/' + url_pas(name), load_lang('discussion'), topic], ['history/' + url_pas(name), load_lang('history')], ['xref/' + url_pas(name), load_lang('backlink')], ['acl/' + url_pas(name), load_lang('acl'), acl]]
+        menu += [
+            ['topic/' + url_pas(name), load_lang('discussion'), topic], 
+            ['history/' + url_pas(name), load_lang('history')], 
+            ['xref/' + url_pas(name), load_lang('backlink')], 
+            ['acl/' + url_pas(name), load_lang('acl'), acl],
+            ['w/' + url_pas(name) + '?reload=true', load_lang('reload')]
+        ]
 
         if flask.request.args.get('from', None):
             menu += [['w/' + url_pas(name), load_lang('pass')]]

+ 4 - 4
version.json

@@ -1,11 +1,11 @@
 {
     "master" : {
-        "r_ver" : "v3.1.5-stable-03",
-        "c_ver" : "400007",
+        "r_ver" : "v3.1.6-stable-01",
+        "c_ver" : "3160032",
         "s_ver" : "7"
     }, "stable" : {
-        "r_ver" : "v3.1.5-stable-03",
-        "c_ver" : "400007",
+        "r_ver" : "v3.1.6-stable-01",
+        "c_ver" : "3160032",
         "s_ver" : "7"
     }
 }

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

@@ -9,7 +9,7 @@ a { text-decoration: none; }
 #not_thing { color: red; }
 #inside, #out_link, #open { color: green; }
 #out_link::before { background: green; color: white; content: "E"; }
-input[type="checkbox"] { width: auto; }
+input[type="checkbox"], input[type="radio"] { width: auto; }
 .popup { position: fixed; bottom: 0; padding: 10px; left: 0; background: lightgray; width: 100%; }
 #list { padding: 10px; }
 #toron { width: 100%; }
@@ -45,4 +45,6 @@ blockquote { background-image: url(/views/acme/img/quote.png); background-positi
 #origin { display: none; }
 .all_in_data { display: block; width: 100%; }
 .table_safe { max-width: 100%; }
-.change_space { white-space: pre; }
+.change_space { white-space: pre-line; }
+div#topic_scroll { max-height: 500px; overflow: scroll; -ms-overflow-style: none; scrollbar-width: none; }
+div#topic_scroll::-webkit-scrollbar { display: none; }

+ 3 - 2
views/main_css/js/do_insert_data.js

@@ -4,13 +4,14 @@ function do_insert_data(name, data) {
     if(document.selection) {
         document.getElementById(name).focus();
 
-        sel = document.selection.createRange();
+        var sel = document.selection.createRange();
         sel.text = data;
     } else if(document.getElementById(name).selectionStart || document.getElementById(name).selectionStart == '0') {
         var startPos = document.getElementById(name).selectionStart;
         var endPos = document.getElementById(name).selectionEnd;
+        var myPos = document.getElementById(name).value;
 
-        document.getElementById(name).value = document.getElementById(name).value.substring(0, startPos) + data + document.getElementById(name).value.substring(endPos, document.getElementById(name).value.length);
+        document.getElementById(name).value = myPos.substring(0, startPos) + data + myPos.substring(endPos, myPos.length);
     } else {
         document.getElementById(name).value += data;
     }

+ 5 - 13
views/main_css/js/do_open_foot.js

@@ -2,20 +2,12 @@ function do_open_foot(name, num = 0) {
     var found_include = name.match(/^(include_(?:[0-9]+)\-)/);
     if(found_include) {
         var include_name = name.replace(/^(?:include_(?:[0-9]+)\-)/, '');
-        document.getElementById(found_include[1] + 'r' + include_name).style.color = 'red';
-        if(num === 1) {
-            document.getElementById(found_include[1] + 'c' + include_name).style.color = 'inherit';
-        } else {
-            document.getElementById(found_include[1] + 'c' + include_name).style.color = 'red';
-        }
+        var front_data = found_include[1];
     } else {
-        document.getElementById('r' + name).style.color = 'red';
-        if(num === 1) {
-            document.getElementById('c' + name).style.color = 'inherit';
-        } else {
-            document.getElementById('c' + name).style.color = 'red';
-        }
+        var include_name = name;
+        var front_data = '';
     }
 
-
+    document.getElementById(front_data + 'r' + include_name).style.color = 'red';
+    document.getElementById(front_data + 'c' + include_name).style.color = (num === 1 ? 'inherit' : 'red');
 }

+ 0 - 33
views/main_css/js/load_include.js

@@ -1,33 +0,0 @@
-function load_include(title, name, p_data) {
-    var o_data = document.getElementById(name);
-
-    var url = "/api/w/" + encodeURI(title) + "?include=" + name;
-
-    var xhr = new XMLHttpRequest();
-    xhr.open("GET", url, true);
-    xhr.send(null);
-
-    xhr.onreadystatechange = function() {
-        if(this.readyState === 4 && this.status === 200) {
-            var o_p_data = JSON.parse(this.responseText);
-            var g_data = o_p_data['data'];
-
-            for(key in p_data) {
-                try {
-                    var patt = new RegExp('@' + p_data[key][0] + '@', 'g');
-                    g_data = g_data.replace(patt, p_data[key][1]);
-                } catch(e) {
-                    console.log(e);
-                }
-            }
-
-            o_data.innerHTML = g_data;
-
-            js_data = o_p_data['js_data'];
-            js_data = js_data.replace(/<script>/g, '');
-            js_data = js_data.replace(/<\/script>/g, '\n');
-
-            eval(js_data)
-        }
-    }
-}

+ 75 - 0
views/main_css/js/load_namumark.js

@@ -0,0 +1,75 @@
+function get_link_state(data, i = 0) { 
+    if(document.getElementsByClassName(data + 'link_finder')[i]) {
+        var link_data = document.getElementsByClassName(data + 'link_finder')[i];
+
+        var xhr = new XMLHttpRequest();
+        xhr.open("GET", link_data.href.replace('/w/', '/api/w/').replace(/#([^#]*)/, '') + "?exist=1", true);
+        xhr.send(null);
+
+        xhr.onreadystatechange = function() {
+            if(this.readyState === 4 && this.status === 200) {
+                if(JSON.parse(this.responseText)['exist'] !== '1') {
+                    document.getElementsByClassName(data + 'link_finder')[i].id = "not_thing";
+                } else {
+                    document.getElementsByClassName(data + 'link_finder')[i].id = "";
+                }
+
+                get_link_state(data, i + 1);
+            }
+        }
+    }
+}
+
+function get_file_state(data, i = 0) {       
+    if(document.getElementsByClassName(data + 'file_finder_1')[i]) {
+        var file_data = document.getElementsByClassName(data + 'file_finder_1')[i];
+
+        var xhr = new XMLHttpRequest();
+        xhr.open("GET", file_data.src.replace('/image/', '/api/image/'), true);
+        xhr.send(null);
+        
+        xhr.onreadystatechange = function() {
+            if(this.readyState === 4 && this.status === 200) {
+                if(JSON.parse(this.responseText)['exist'] !== '1') {
+                    document.getElementsByClassName(data + 'file_finder_1')[i].style = "display: none;";
+                } else {
+                    document.getElementsByClassName(data + 'file_finder_2')[i].innerHTML = "";
+                }
+            
+                get_file_state(data, i + 1);
+            }
+        }
+    }
+}
+
+function load_include(title, name, p_data) {
+    var o_data = document.getElementById(name);
+
+    var change = '';
+    for(key in p_data) {
+        change += '@' + p_data[key][0].replace('&', '<amp>') + '@,' + p_data[key][1].replace(',', '<comma>').replace('&', '<amp>') + ','
+    }
+    
+    var url = "/api/w/" + encodeURI(title) + "?include=" + name + "&change=" + change;
+
+    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 === "{}\n") {
+                o_data.innerHTML = "";
+
+                document.getElementsByClassName(name)[0].id = "not_thing";
+            } else {
+                var o_p_data = JSON.parse(this.responseText);
+                
+                var g_data = o_p_data['data'];
+                o_data.innerHTML = g_data;
+
+                eval(o_p_data['js_data']);
+            }
+        }
+    }
+}

+ 1 - 7
views/main_css/js/load_preview.js

@@ -19,14 +19,8 @@ function load_preview(name) {
     xhr.onreadystatechange = function() {
         if(xhr.readyState === 4 && xhr.status === 200) {
             var o_p_data = JSON.parse(xhr.responseText);
-
             p_data.innerHTML = o_p_data['data'];
-
-            js_data = o_p_data['js_data'];
-            js_data = js_data.replace(/<script>/g, '');
-            js_data = js_data.replace(/<\/script>/g, '\n');
-
-            eval(js_data)
+            eval(o_p_data['js_data'])
         }
     }
 }

+ 138 - 0
views/main_css/js/load_topic.js

@@ -0,0 +1,138 @@
+function topic_list_load(topic_num, s_num, where) {
+    var o_data = document.getElementById(where);
+    var url = "/api/thread/" + String(topic_num) + "?render=1&num=" + String(s_num);
+    var n_data = "";
+
+    var xhr = new XMLHttpRequest();
+    xhr.open("GET", url, true);
+    xhr.send(null);
+
+    xhr.onreadystatechange = function() {
+        if(this.readyState === 4 && this.status === 200) {
+            var t_data = JSON.parse(this.responseText);
+            var t_plus_data = '';
+            
+            for(key in t_data) {
+                n_data += t_data[key]['data'];
+                t_plus_data += t_data[key]['plus_data'];
+            }
+
+            o_data.innerHTML = n_data;
+            eval(t_plus_data);
+        }
+    }
+}
+
+function topic_plus_load(topic_num, num) {
+    var test = setInterval(function() {
+        var url = "/api/thread/" + String(topic_num) + "?num=" + num + "&render=1";
+        var 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') {
+                var t_data = JSON.parse(this.responseText);
+                var t_plus_data = '';
+
+                for(key in t_data) {
+                    n_data += t_data[key]['data'];
+                    n_num = key;
+
+                    t_plus_data += t_data[key]['plus_data'];
+                }
+
+                p_data.innerHTML += n_data;
+                eval(t_plus_data);
+
+                // https://programmingsummaries.tistory.com/379
+                var options = {
+                    body: '#' + n_num
+                }
+
+                var notification = new Notification("openNAMU", options);
+
+                setTimeout(function () {
+                    notification.close();
+                }, 5000);
+
+                topic_plus_load(topic_num, String(Number(num) + 1));
+                clearInterval(test);
+            }
+        }
+    }, 2000);
+}
+
+function topic_main_load(topic_num, s_num) {
+    var o_data = document.getElementById('main_topic');
+    if(s_num) {
+        var url = "/api/thread/" + String(topic_num) + "?render=1&num=" + s_num;
+    } else {
+        var url = "/api/thread/" + String(topic_num) + "?render=1";
+    }
+    var n_data = "";
+    var num = 1;
+
+    var xhr = new XMLHttpRequest();
+    xhr.open("GET", url, true);
+    xhr.send(null);
+
+    xhr.onreadystatechange = function() {
+        if(xhr.readyState === 4 && xhr.status === 200) {
+            var t_data = JSON.parse(xhr.responseText);
+            var t_plus_data = '';
+
+            for(var key in t_data) {
+                n_data += t_data[key]['data'];
+                num = key;
+
+                t_plus_data += t_data[key]['plus_data'];
+            }
+
+            o_data.innerHTML = n_data;
+            eval(t_plus_data);
+            if(window.location.search === "?where=bottom") {
+                document.getElementById(num).focus();
+            }
+            
+            if(!s_num) {
+                topic_plus_load(topic_num, String(Number(num) + 1));
+            }
+        }
+    }
+}
+
+function topic_top_load(topic_num) {
+    var o_data = document.getElementById('top_topic');
+    var url = "/api/thread/" + String(topic_num) + "?top=1&render=1";
+    var n_data = "";
+    var num = 1;
+
+    var xhr = new XMLHttpRequest();
+    xhr.open("GET", url, true);
+    xhr.send(null);
+
+    xhr.onreadystatechange = function() {
+        if(this.readyState === 4 && this.status === 200) {
+            var t_data = JSON.parse(this.responseText);
+            var t_plus_data = '';
+
+            for(var key in t_data) {
+                n_data += t_data[key]['data'];
+                num = key;
+
+                t_plus_data += t_data[key]['plus_data'];
+            }
+
+            o_data.innerHTML = n_data;
+            eval(t_plus_data);
+
+            topic_main_load(topic_num, null);
+        }
+    }
+
+}

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

@@ -1,10 +0,0 @@
-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;
-}

+ 0 - 531
views/main_css/js/render_namumark.js

@@ -1,531 +0,0 @@
-function render_namumark(target) {
-    function get_today() {
-        var today_data = new Date();
-
-        return '' +
-            String(today_data.getFullYear()) + '-' + 
-            String(today_data.getMonth() + 1) + '-' + 
-            String(today_data.getDate()) + ' ' + 
-            (today_data.getHours() < 10 ? '0' + String(today_data.getHours()) : String(today_data.getHours())) + ':' + 
-            (today_data.getMinutes() < 10 ? '0' + String(today_data.getMinutes()) : String(today_data.getMinutes())) + ':' + 
-            (today_data.getSeconds() < 10 ? '0' + String(today_data.getSeconds()) : String(today_data.getSeconds())) +
-        '';
-    }
-
-    function get_link_state(link_data) {            
-        var xhr = new XMLHttpRequest();
-        xhr.open("GET", "/api/w/" + encodeURIComponent(link_data[0]) + "?exist=1", true);
-        xhr.send(null);
-        
-        xhr.onreadystatechange = function() {
-            if(this.readyState === 4 && this.status === 200) {
-                if(JSON.parse(this.responseText)['exist'] !== '1') {
-                    document.getElementsByClassName(link_data[1])[0].id = "not_thing";
-                } else {
-                    document.getElementsByClassName(link_data[1])[0].id = "";
-                }
-            } else {
-                document.getElementsByClassName(link_data[1])[0].id = "not_thing";
-            }
-        }
-    }
-
-    function get_file_state(file_data) {            
-        var file_part = file_data[0].match(/^([^.]+)\.(.+)$/);
-        if(file_part) {
-            var file_name = file_part[1];
-            var file_type = '.' + file_part[2];
-        } else {
-            var file_name = file_data;
-            var file_type = '';
-        }
-
-        var xhr = new XMLHttpRequest();
-        xhr.open("GET", "/api/sha224/" + encodeURIComponent(file_name), true);
-        xhr.send(null);
-        
-        xhr.onreadystatechange = function() {
-            if(this.readyState === 4 && this.status === 200) {
-                var xhr = new XMLHttpRequest();
-                xhr.open("GET", "/api/w/file:" + encodeURIComponent(file_data[0]) + "?exist=1", true);
-                xhr.send(null);
-
-                var img_src = JSON.parse(this.responseText)['data'];
-                
-                xhr.onreadystatechange = function() {
-                    if(this.readyState === 4 && this.status === 200) {
-                        if(JSON.parse(this.responseText)['exist'] !== '1') {
-                            document.getElementById(file_data[1]).innerHTML = '' +
-                                '<a href="/upload?name=' + encodeURIComponent(file_data[0]) + '" id="not_thing">' + file_data[0] + '</a>' +
-                            '';
-                        } else {
-                            document.getElementById(file_data[1]).innerHTML = '' +
-                                '<img src="/image/' + img_src + file_type + '">' +
-                            '';
-                        }
-                    } else {
-                        console.log(file_data[1]);
-                        document.getElementById(file_data[1]).innerHTML = '' +
-                            '<a href="/upload?name=' + encodeURIComponent(file_data[0]) + '" id="not_thing">' + file_data[0] + '</a>' +
-                        '';
-                    }
-                }
-            }
-        }
-    }
-
-    function divi_link(link_data) {
-        var link_part = link_data.match(/^([^|]+)\|(.+)$/);
-        if(link_part) {
-            return [link_part[2], link_part[1]]
-        } else {
-            return [link_data, link_data]
-        }
-    }
-
-    var data = '\n' + document.getElementById(target).innerHTML + '\n';
-
-    var mid_num = 0;
-    var mid_stack = 0;
-    var mid_list = [];
-    var html_number = 0;
-    data = data.replace(/(?:{{{(?:((?:(?! |{{{|}}}|&lt;).)*) ?)|(}}}))/g, function(all, in_data) {
-        if(all === '}}}') {
-            if(mid_stack > 0) {
-                mid_stack -= 1;
-            }
-
-            if(mid_stack > 0) {
-                return all;
-            } else {
-                if(mid_num > 0) {
-                    mid_num -= 1;
-                }
-
-                if(!mid_list[mid_num]) {
-                    var return_data = '';
-                } else if(mid_list[mid_num] === 'pre') {
-                    var return_data = '</code></pre>';
-                } else {
-                    var return_data = '</' + mid_list[mid_num] + '>';
-                }
-
-                if(return_data !== '') {
-                    mid_list.splice(mid_num, 1);
-
-                    return return_data;
-                } else {
-                    return all;
-                }
-            }
-        } else {
-            if(mid_stack > 0) {
-                mid_stack += 1;
-
-                return all;
-            } else {
-                mid_num += 1;
-
-                if(in_data.match(/^(#|@|\+|\-)/) && !in_data.match(/^(#|@|\+|\-){2}|(#|@|\+|\-)\\\\/)) {                    
-                    if(in_data.match(/^((#|@)([0-9a-f-A-F]{3}){1,2})/)) {
-                        mid_list.push('span');
-
-                        if(in_data.match(/^#/)) {
-                            return '<span style="color: ' + in_data + ';">';
-                        } else {
-                            return '<span style="background: ' + in_data + ';">';
-                        }
-                    } else if(in_data.match(/^((#|@)(\w+))/)) {
-                        mid_list.push('span');
-
-                        if(in_data.match(/^#/)) {
-                            return '<span style="color: ' + in_data.replace(/^#/, '') + ';">';
-                        } else {
-                            return '<span style="background: ' + in_data.replace(/^@/, '') + ';">';
-                        }
-                    } else if(in_data.match(/^(\+|-)([1-5])/)) {
-                        mid_list.push('span');
-
-                        var font_size_data = in_data.match(/^(\+|-)([1-5])/);
-                        if(font_size_data[1] == '+') {
-                            font_size_data = String(Number(font_size_data[2]) * 20 + 100);
-                        } else {
-                            font_size_data = String(100 - Number(font_size_data[2]) * 10);
-                        }
-
-                        return '<span style="font-size: ' + font_size_data + '%;">'
-                    } else if(in_data.match(/#!wiki/i)) {
-                        mid_list.push('div');
-
-                        if(data.match(/{{{#!wiki style=((?:(?!\n).)+) *\n/i)) {
-                            return '<div id="wiki_div_before">';
-                        } else {
-                            return '<div id="wiki_div">'
-                        }
-                    } else if(in_data.match(/#!syntax/i)) {
-                        mid_list.push('pre');
-                        mid_stack += 1;
-                        
-                        return '<pre><code id="syntax_before">';
-                    } else if(in_data.match(/#!folding/i)) {
-                        mid_list.push('div');
-                        
-                        return '<div id="folding_before">';
-                    } else if(in_data.match(/#!html/i)) {
-                        mid_list.push('span');
-                        html_number += 1;
-
-                        return '<span id="html_render_contect_' + String(html_number) + '">';
-                    } else {
-                        mid_list.push('code');
-                        mid_stack += 1;
-    
-                        return '<code>' + in_data;
-                    }
-                } else {
-                    mid_list.push('code');
-                    mid_stack += 1;
-
-                    return '<code>' + in_data;
-                }
-            }
-        }
-    });
-
-    console.log(mid_stack);
-    console.log(mid_num);
-    console.log(mid_list);
-
-    data = data.replace(/<\/div> *\n/ig, '</div>');
-
-    data = data.replace(/<div id="folding_before">((?:(?!\n).)+) *\n/ig, function(all, in_data) {
-        return in_data + ' [+]<div id="folding">';
-    });
-    
-    data = data.replace(/<pre><code id="syntax_before">((?:(?!\n).)+) *\n/ig, function(all, in_data) {
-        return '<pre><code>';
-    });
-
-    data = data.replace(/<div id="wiki_div_before">style=((?:(?!\n).)+) *\n/ig, function(all, in_data) {
-        return '<div style=' + in_data.replace(/&quot;/g, "\"").replace(/&#039;/g, "'") + ' id="wiki_div">';
-    });
-
-    var nowiki_num = 0;
-    var nowiki_list = {};
-    data = data.replace(/<code>((?:(?!<\/code>).)+)<\/code>/gm, function(all, in_data) {
-        nowiki_num += 1;
-        nowiki_list['nowiki_' + String(nowiki_num)] = in_data;
-
-        return '<span id="nowiki_' + String(nowiki_num) + '"></span>';
-    });
-
-    var math_list = [];
-    var math_num = 0;
-    data = data.replace(/\[math\(((?:(?!\)]).)+)\)]/ig, function(all, in_data) {
-        var math_data = in_data.replace(/&amp;/g, "&").replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&quot;/g, "\"").replace(/&#039;/g, "'");
-
-        math_num += 1;
-        math_list.push(['math_' + String(math_num), math_data]);
-
-        return '<span id="math_' + String(math_num) + '"></span>';
-    });
-
-    data = data.replace(/~~((?:(?!~~).)+)~~/g, '<s>$1</s>');
-    data = data.replace(/--((?:(?!--).)+)--/g, '<s>$1</s>');
-    data = data.replace(/__((?:(?!__).)+)__/g, '<u>$1</u>');
-    data = data.replace(/'''((?:(?!''').)+)'''/g, '<b>$1</b>');
-    data = data.replace(/''((?:(?!'').)+)''/g, '<i>$1</i>');
-    data = data.replace(/\^\^((?:(?!\^\^).)+)\^\^/g, '<sup>$1</sup>');
-    data = data.replace(/,,((?:(?!,,).)+),,/g, '<sub>$1</sub>');
-
-    data = data.replace(/\n( {1,})\* ([^\n]+)/g, function(all, margin_data, in_data) {
-        return '<li style="margin-left: ' + String(margin_data.length * 20) + 'px;">' + in_data + '</li>'
-    });
-
-    data = data.replace(/\n( {1,})/g, function(all, margin_data) {
-        return '\n<span style="margin-left: ' + String(margin_data.length * 10) + 'px"></span>'
-    });
-
-    var link_list = [];
-    var file_list = [];
-    var link_num = 0;
-    var file_num = 0;
-    var category = '<div id="cate_all"><hr><div id="cate">Category : '
-    data = data.replace(/\[\[((?:(?!]]).)+)]]/g, function(all, in_data) {
-        if(in_data.match(/^(?:category|분류):/i)) {
-            category += '<a href="' + encodeURIComponent(in_data) + '">' + in_data + '</a> | ';
-
-            return '';
-        } else if(in_data.match(/^(?:file|파일):/i)) {
-            file_list.push([in_data.replace(/^(?:file|파일):/i, ''), 'file_' + String(file_num)]);
-            file_num += 1;
-            
-            return '<span id="file_' + String(file_num - 1) + '"></span>';
-        } else if(in_data.match(/^http(?:s)?:\/\//i)) {
-            var link_part = divi_link(in_data);
-            
-            var front_data = link_part[0];
-            var back_data = link_part[1];
-
-            return '<a id="out_link" href="' + back_data + '">' + front_data + '</a>'; 
-        } else {
-            var link_part = divi_link(in_data);
-            
-            var front_data = link_part[0];
-            var back_data = link_part[1];
-
-            link_list.push([back_data, 'link_' + String(link_num)]);
-            link_num += 1;
-
-            return '<a class="link_' + String(link_num - 1) + '" href="/w/' + encodeURIComponent(back_data) + '">' + front_data + '</a>'; 
-        }
-    });
-
-    data = data.replace(/\[([^(\]]+)\(((?:(?!\)]).)+)\)]/g, function(all, name, in_data) {
-        if(name.match(/^youtube|kakaotv|nicovideo$/i)) {
-            var video_code = in_data.match(/^([^,]+)/);
-            if(video_code) {
-                video_code = video_code[1];
-            } else {
-                video_code = 'test';
-            }
-
-            if(name === 'youtube') {
-                var video_src = 'https://www.youtube.com/embed/' + video_code
-            } else if(name === 'kakaotv') {
-                var video_src = 'https://tv.kakao.com/embed/player/cliplink/' + video_code +'?service=kakao_tv'
-            } else {
-                var video_src = 'https://embed.nicovideo.jp/watch/' + video_code
-            }
-
-            var width_data = in_data.match(/, *width=([^,]+)/);
-            if(width_data) {
-                width_data = width_data[1];
-            } else {
-                width_data = '560';
-            }
-
-            var height_data = in_data.match(/, *height=([^,]+)/);
-            if(height_data) {
-                height_data = height_data[1];
-            } else {
-                height_data = '315';
-            }
-
-            return '' +
-                '<iframe ' +
-                    'width="' + width_data + '" ' +
-                    'height="' + height_data + '" ' +
-                    'src="' + video_src + '" ' +
-                    'allowfullscreen>' +
-                '</iframe>' +
-            '';
-        } else if(name.match(/^ruby$/i)) {
-            var main_text = in_data.match(/^([^,]+)/);
-            if(main_text) {
-                main_text = main_text[1];
-            } else {
-                main_text = 'test';
-            }
-
-            var ruby_text = in_data.match(/, *ruby=([^,]+)/);
-            if(ruby_text) {
-                ruby_text = ruby_text[1];
-            } else {
-                ruby_text = 'test';
-            }
-
-            var color_text = in_data.match(/, *color=([^,]+)/);
-            if(color_text) {
-                color_text = 'color:' + color_text[1];
-            } else {
-                color_text = '';              
-            }
-
-            return '' +
-                '<ruby>' +
-                    main_text +
-                    '<rp>(</rp>' +
-                    '<rt>' +
-                        '<span style="' + color_text + '">' + ruby_text + '</span>' +
-                    '</rt>' +
-                    '<rp>)</rp>' +
-                '</ruby>' +
-            '';
-        } else if(name.match(/^anchor$/i)) {
-            return '<span id="' + in_data + '"></span>';
-        } else {
-            return all;
-        }
-    });
-
-    var toc_array = [0, 0, 0, 0, 0, 0];
-    var before_data = 0;
-    var toc_data = '<div id="toc"><span id="toc_title">TOC</span>\n\n'
-    data = data.replace(/\n(={1,6}) ?([^\n]+) (?:={1,6})/g, function(all, num, in_data) {
-        num = num.length;
-        
-        if(before_data > num) {
-            var i = num;
-            while(1) {
-                if(i == 6) {
-                    break;
-                }
-
-                toc_array[i] = 0;
-                i += 1;
-            }
-        }
-
-        before_data = num;
-        toc_array[num - 1] += 1;
-        num = String(num);
-        var toc_num = (toc_array.join('.') + '.').replace(/0\./g, '');
-        if(!toc_num.match(/\./)) {
-            toc_num += '0.';
-        }
-
-        toc_data += '' + 
-            '<span style="margin-left: ' + String(10 * (toc_num.length / 2) - 10) + 'px;">' + 
-                '<a href="#s-' + toc_num.replace(/\.$/, '') + '">' + toc_num + '</a> ' + in_data + 
-            '</span>' +
-            '\n' + 
-        '';
-
-        return '\n<h' + num + ' id="s-' + toc_num.replace(/\.$/, '') + '"><a href="#toc">' + toc_num + '</a> ' + in_data + '</h' + num + '>';
-    });
-
-    toc_data += '</div>';
-    data = data.replace(/<\/h([0-9])>\n/g, '</h$1>');
-
-    data = data.replace(/\[([^\]]+)\]/g, function(all, name) {
-        if(name.match(/^br$/i)) {
-            return '\n'
-        } else if(name.match(/^목차$/i)) {
-            return toc_data;
-        } else if(name.match(/^date|datetime$/i)) {
-            return get_today();
-        } else {
-            return all;
-        }
-    });
-
-    var ref_num = 0;
-    var ref_data = '<hr><ul id="footnote_data">';
-    var name_ref_data = {};
-    data = data.replace(/(?:\[\*([^ \]]*)(?: ([^\]]+))?\]|\[(?:각주|footnote)])/g, function(all, name_data, in_data) {
-        if(all.match(/^\[(?:각주|footnote)]$/i)) {
-            var new_ref_data = ref_data;
-            ref_data = '<hr><ul id="footnote_data">';
-            
-            return new_ref_data + '</ul>';
-        } else {
-            ref_num += 1;
-            if(name_data) {
-                if(in_data) {
-                    name_ref_data[name_data] = in_data;
-
-                    ref_data += '' +
-                        '<li>' +
-                            '<a id="fn-' + name_data + '" href="#rfn-' + String(ref_num) + '">(' + name_data + ')</a> ' + in_data + ''
-                        '</li>' +
-                    ''    
-                } else {
-                    ref_data += '' +
-                        '<li>' +
-                            '<a href="#rfn-' + String(ref_num) + '">(' + name_data + ')</a>' +
-                        '</li>' +
-                    ''
-                }
-            } else {
-                ref_data += '' +
-                    '<li>' +
-                        '<a id="fn-' + String(ref_num) + '" href="#rfn-' + String(ref_num) + '">(' + String(ref_num) + ')</a> ' + in_data + ''
-                    '</li>' +
-                ''
-            }
-
-            if(name_data) {
-                return '' +
-                    '<sup>' +
-                        '<a href="#fn-' + name_data + '" id="rfn-' + String(ref_num) + '" title="' + name_ref_data[name_data].replace(/<([^>]*)>/g, '') + '">' +
-                            '(' + name_data + ')' +
-                        '</a>' +
-                    '</sup>' +
-                '';
-            } else {
-                return '' +
-                '<sup>' +
-                    '<a href="#fn-' + String(ref_num) + '" id="rfn-' + String(ref_num) + '" title="' + in_data.replace(/<([^>]*)>/g, '') + '">' +
-                        '(' + String(ref_num) + ')' +
-                    '</a>' +
-                '</sup>' +
-            '';
-            }
-        }
-    });
-
-    if(ref_data !== '<hr><ul id="footnote_data">') {
-        data += ref_data + '</ul>';
-    }
-
-    var i = 1;
-    while(1) {
-        if(nowiki_list['nowiki_' + String(i)]) {
-            data = data.replace('<span id="nowiki_' + String(i) + '"></span>', '<code>' + nowiki_list['nowiki_' + String(i)] + '</code>');
-
-            i += 1;
-        } else {
-            break;
-        }
-    }
-
-    data = data.replace(/^(\n| )+/g, '');
-    data = data.replace(/(\n| )+$/g, '');
-    data = data.replace(/\n/g, '<br>');
-
-    data = data.replace(/&amp;/g, '&');
-
-    document.getElementById(target).innerHTML = data;
-
-    i = 0;
-    while(1) {
-        if(math_list[i]) {
-            try {
-                katex.render(math_list[i][1], document.getElementById(math_list[i][0]));
-            } catch {
-                try {
-                    document.getElementById(math_list[i][0]).innerHTML = '<span style="color: red;">' + math_list[i][1] + '</span>';
-                } catch {}
-            }
-
-            i += 1;
-        } else {
-            break;
-        }
-    }
-
-    i = 0;
-    while(1) {
-        if(link_list[i]) {
-            get_link_state(link_list[i]);
-
-            i += 1;
-        } else {
-            break;
-        }
-    }
-
-    i = 0;
-    while(1) {
-        if(file_list[i]) {
-            get_file_state(file_list[i]);
-
-            i += 1;
-        } else {
-            break;
-        }
-    }
-
-    render_html("html_render_contect");    
-}

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

@@ -1,23 +0,0 @@
-function topic_list_load(topic_num, s_num, where) {
-    var o_data = document.getElementById(where);
-    var url = "/api/thread/" + String(topic_num) + "?render=1&num=" + String(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 - 49
views/main_css/js/topic_main_load.js

@@ -1,49 +0,0 @@
-function topic_main_load(topic_num, s_num) {
-    var o_data = document.getElementById('main_topic');
-    if(s_num) {
-        var url = "/api/thread/" + String(topic_num) + "?render=1&num=" + s_num;
-    } else {
-        var url = "/api/thread/" + String(topic_num) + "?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(var key in t_data) {
-                n_data += t_data[key]['data'];
-                num = key;
-            }
-
-            o_data.innerHTML = n_data;
-            if(!s_num) {
-                topic_plus_load(topic_num, 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();
-                    } else {
-                        for(var key in t_data) {
-                            render_html('topic_' + String(key) + '-');
-                        }
-                    }
-                }
-            }
-        }
-    }
-
-}

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

@@ -1,57 +0,0 @@
-function topic_plus_load(topic_num, num) {
-    var test = setInterval(function() {
-        var url = "/api/thread/" + String(topic_num) + "?num=" + num + "&render=1";
-        var p_data = document.getElementById("plus_topic");
-        var n_data = '';
-        var n_num = 1;
-        var url_2 = "/api/markup";
-
-        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(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: '#' + n_num
-                }
-
-                var notification = new Notification("openNAMU", options);
-
-                setTimeout(function () {
-                    notification.close();
-                }, 5000);
-
-                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();
-                        } else {
-                            for(var key in t_data) {
-                                render_html('topic_' + String(key) + '-');
-                            }
-                        }
-                    }
-                }
-
-                topic_plus_load(topic_num, String(Number(num) + 1));
-                clearInterval(test);
-            }
-        }
-    }, 2000);
-}

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

@@ -1,24 +0,0 @@
-function topic_top_load(topic_num) {
-    var o_data = document.getElementById('top_topic');
-    var url = "/api/thread/" + String(topic_num) + "?top=1&render=1";
-    var n_data = "";
-    var num = 1;
-
-    var xhr = new XMLHttpRequest();
-    xhr.open("GET", url, true);
-    xhr.send(null);
-
-    xhr.onreadystatechange = function() {
-        if(this.readyState === 4 && this.status === 200) {
-            t_data = JSON.parse(this.responseText);
-            for(var key in t_data) {
-                n_data += t_data[key]['data'];
-                num = key;
-            }
-
-            o_data.innerHTML = n_data;
-            topic_main_load(topic_num, null);
-        }
-    }
-
-}

+ 4 - 0
views/marisa/css/dark.css

@@ -46,4 +46,8 @@ textarea, input, button, select {
 
 pre#syntax {
     background: black;
+}
+
+a#titlt_a {
+    color: white;
 }

+ 1 - 2
views/marisa/index.html

@@ -9,10 +9,9 @@
         {% endif %}
         {{imp[3][3]|safe}}
         <link rel="stylesheet" href="/views/marisa/css/main.css?ver=7">
-        <script src="/views/marisa/js/search.js?ver=2"></script>
         <script src="/views/marisa/js/skin_set.js?ver=3"></script>
         <script src="/views/marisa/js/main.js?ver=3"></script>
-        <script>window.onload = function () { search_do(); skin_set(); }</script>
+        <script>window.onload = function () { skin_set(); }</script>
         <script src="https://code.iconify.design/1/1.0.3/iconify.min.js"></script>
         <link rel="shortcut icon" href="/views/main_css/file/favicon.ico?ver=1">
         {{imp[1][5]|safe}}

+ 1 - 1
views/marisa/info.json

@@ -1,5 +1,5 @@
 {
     "name" : "Marisa",
-    "skin_ver" : "v1.1.6",
+    "skin_ver" : "v1.1.7",
     "require_ver" : "7"
 }

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

@@ -63,7 +63,7 @@ function main_load() {
         cookies.match(regex_data('invert')) &&
         cookies.match(regex_data('invert'))[1] === '1'
     ) {
-        head_data.innerHTML += '<link rel="stylesheet" href="/views/marisa/css/dark.css?ver=4">';
+        head_data.innerHTML += '<link rel="stylesheet" href="/views/marisa/css/dark.css?ver=5">';
     }
 }