Przeglądaj źródła

Merge pull request #1532 from openNAMU/dev

모르겠당
잉여개발기 (SPDV) 3 lat temu
rodzic
commit
6de1b4783c
100 zmienionych plików z 4833 dodań i 2964 usunięć
  1. 26 10
      .dockerignore
  2. 14 8
      .github/ISSUE_TEMPLATE.md
  3. 4 4
      .gitignore
  4. 3 3
      Docker-Install.md
  5. 2 1
      Dockerfile
  6. 2 1
      Dockerfile.arm64v8
  7. 21 0
      Dockerfile.arm64v8.ko
  8. 21 0
      Dockerfile.ko
  9. 254 179
      app.py
  10. 42 3
      emergency_tool.py
  11. 67 16
      lang/en-US.json
  12. 58 14
      lang/ko-KR.json
  13. 18 0
      route/api_func_lang.py
  14. 18 0
      route/api_func_sha224.py
  15. 18 17
      route/api_image_view.py
  16. 0 12
      route/api_markup.py
  17. 0 17
      route/api_sha224.py
  18. 0 56
      route/api_sitemap.py
  19. 76 0
      route/api_topic.py
  20. 0 65
      route/api_topic_sub.py
  21. 53 75
      route/api_user_info.py
  22. 121 60
      route/edit.py
  23. 2 2
      route/edit_delete.py
  24. 1 1
      route/edit_delete_multiple.py
  25. 81 30
      route/edit_move.py
  26. 1 1
      route/edit_revert.py
  27. 14 9
      route/edit_upload.py
  28. 2 2
      route/filter_inter_wiki_add.py
  29. 122 115
      route/give_acl.py
  30. 56 55
      route/give_admin.py
  31. 58 57
      route/give_admin_groups.py
  32. 22 21
      route/give_delete_admin_group.py
  33. 124 101
      route/give_user_ban.py
  34. 163 162
      route/give_user_check.py
  35. 44 43
      route/give_user_check_delete.py
  36. 31 30
      route/list_acl.py
  37. 19 18
      route/list_admin.py
  38. 27 26
      route/list_admin_group.py
  39. 31 30
      route/list_admin_use.py
  40. 17 19
      route/list_image_file.py
  41. 18 17
      route/list_long_page.py
  42. 24 23
      route/list_please.py
  43. 60 59
      route/list_title_index.py
  44. 20 19
      route/list_user.py
  45. 11 10
      route/login_find.py
  46. 60 59
      route/login_login.py
  47. 58 57
      route/login_login_2fa.py
  48. 53 52
      route/login_login_2fa_email.py
  49. 4 3
      route/login_logout.py
  50. 120 113
      route/login_register.py
  51. 56 55
      route/login_register_email.py
  52. 43 42
      route/login_register_email_check.py
  53. 56 57
      route/login_register_submit.py
  54. 11 4
      route/main_error_404.py
  55. 17 15
      route/main_func_setting.py
  56. 8 1
      route/main_func_setting_acl.py
  57. 3 3
      route/main_func_setting_external.py
  58. 13 8
      route/main_func_setting_head.py
  59. 48 21
      route/main_func_setting_main.py
  60. 1 1
      route/main_func_setting_main_logo.py
  61. 20 5
      route/main_func_setting_phrase.py
  62. 23 35
      route/main_func_setting_robot.py
  63. 116 0
      route/main_func_setting_sitemap.py
  64. 2 1
      route/main_search.py
  65. 27 31
      route/main_search_deep.py
  66. 26 25
      route/main_sys_restart.py
  67. 20 17
      route/main_sys_shutdown.py
  68. 5 5
      route/main_sys_update.py
  69. 13 65
      route/main_tool_admin.py
  70. 0 0
      route/main_tool_guide.py
  71. 54 53
      route/main_tool_other.py
  72. 61 0
      route/main_tool_redirect.py
  73. 24 23
      route/main_view.py
  74. 21 8
      route/main_view_file.py
  75. 13 12
      route/main_view_image.py
  76. 138 137
      route/recent_app_submit.py
  77. 130 129
      route/recent_block.py
  78. 19 7
      route/recent_change.py
  79. 17 6
      route/recent_history_add.py
  80. 2 2
      route/recent_history_tool.py
  81. 343 168
      route/tool/func.py
  82. 19 30
      route/tool/func_render.py
  83. 1001 79
      route/tool/func_render_namumark.py
  84. 71 31
      route/topic.py
  85. 6 3
      route/topic_comment_blind.py
  86. 7 3
      route/topic_comment_notice.py
  87. 5 2
      route/topic_comment_tool.py
  88. 4 9
      route/topic_list.py
  89. 28 7
      route/topic_tool.py
  90. 42 13
      route/topic_tool_acl.py
  91. 9 9
      route/topic_tool_change.py
  92. 55 25
      route/topic_tool_setting.py
  93. 1 7
      route/user_alarm.py
  94. 5 5
      route/user_challenge.py
  95. 47 3
      route/user_count.py
  96. 2 3
      route/user_info.py
  97. 5 12
      route/user_setting.py
  98. 60 59
      route/user_setting_email.py
  99. 43 42
      route/user_setting_email_check.py
  100. 32 11
      route/user_setting_head.py

+ 26 - 10
.dockerignore

@@ -1,18 +1,34 @@
-.git
-.gitignore
-Dockerfile
-.dockerignore
-*.md
-
-set_mark/__pycache__
-/__pycache__
+__pycache__
 /app_session
+
+data/set.json
+data/mysql.json
+data/oauthsettings.json
+data/version.json
+
+route/tool/set_mark/custom.py
+
+images
+
 .vscode
+goorm.manifest
+.DS_Store
 
 *.db
+*.db-shm
+*.db-wal
+*.db-journal
+
+robots.txt
+custom.py
+404.html
 
 views/liberty
-views/yousoro
-views/super_lite
 views/buma
 views/before_namu
+views/acme
+views/sl_open
+views/nitori
+
+sitemap.xml
+sitemap_0.xml

+ 14 - 8
.github/ISSUE_TEMPLATE.md

@@ -1,13 +1,19 @@
-## Environment (환경)
-* OS :
-* Python version :
-* openNAMU version :
-* Skin : 
-* Skin version : 
+## 환경 (Environment)
+* 운영체제 (OS) :
+* 파이썬 버전 (Python version) :
+* 오픈나무 버전 (openNAMU version) :
+* 사용하는 브랜치 (Branch that you use) :
+* 스킨 (Skin) : 
+* 스킨 버전 (Skin version) : 
 
 <!-- 무언가 작동 안할 때는 캐시 초기화를 먼저 해보세요. -->
 <!-- Try initializing the cache first when something isn't working. -->
 
-## Explanation (설명)
+## 설명 (Explanation)
 
-## Screenshot (스크린샷)
+## 오류 내용 (Error contents)
+
+## 스크린샷 (Screenshot)
+
+<!-- 다 작성해주시면 오류 해결에 좀 더 빠른 시간이 소요됩니다. -->
+<!-- If you fill it out, it will take faster time to resolve the error. -->

+ 4 - 4
.gitignore

@@ -9,7 +9,10 @@ data/version.json
 route/tool/set_mark/custom.py
 
 images
+
 .vscode
+goorm.manifest
+.DS_Store
 
 *.db
 *.db-shm
@@ -20,8 +23,6 @@ robots.txt
 custom.py
 404.html
 
-goorm.manifest
-
 views/liberty
 views/buma
 views/before_namu
@@ -29,6 +30,5 @@ views/acme
 views/sl_open
 views/nitori
 
-.DS_Store
 sitemap.xml
-sitemap_0.xml
+sitemap_0.xml

+ 3 - 3
Docker-Install.md

@@ -1,10 +1,10 @@
 ## Installation
 ```
-docker pull opennamu/stable
+docker pull opennamu/opennamu
 ```
 
 ## Start
 ```
-docker run -p 3000:3000 -v data:/app/data --name opennamu opennamu/stable
-docker run -p <host-port>:3000 -v <host-data_directory>:/app/data --name <docker-containername> opennamu/stable
+docker run -p 3000:3000 -v data:/app/data --name opennamu opennamu/opennamu
+docker run -p <host-port>:3000 -v <host-data_directory>:/app/data --name <docker-containername> opennamu/opennamu
 ```

+ 2 - 1
Dockerfile

@@ -1,4 +1,4 @@
-FROM python:3.6.8-stretch
+FROM python:3.10.5-alpine
 
 MAINTAINER 2du <min08101@naver.com>
 MAINTAINER hoparkgo9ma <me@ho9.me>
@@ -10,6 +10,7 @@ ENV NAMU_PORT 3000
 ENV NAMU_LANG en-US
 ENV NAMU_MARKUP namumark
 ENV NAMU_ENCRYPT sha3
+ENV NAMU_DOCKER O
 
 ADD . /app
 WORKDIR /app

+ 2 - 1
Dockerfile.arm64v8

@@ -1,4 +1,4 @@
-FROM arm64v8/python:3.6.8-stretch
+FROM arm64v8/3.10.5-alpine
 
 MAINTAINER 2du <min08101@naver.com>
 MAINTAINER hoparkgo9ma <me@ho9.me>
@@ -10,6 +10,7 @@ ENV NAMU_PORT 3000
 ENV NAMU_LANG en-US
 ENV NAMU_MARKUP namumark
 ENV NAMU_ENCRYPT sha3
+ENV NAMU_DOCKER O
 
 ADD . /app
 WORKDIR /app

+ 21 - 0
Dockerfile.arm64v8.ko

@@ -0,0 +1,21 @@
+FROM arm64v8/3.10.5-alpine
+
+MAINTAINER 2du <min08101@naver.com>
+MAINTAINER hoparkgo9ma <me@ho9.me>
+
+ENV NAMU_DB_TYPE sqlite
+ENV NAMU_DB data
+ENV NAMU_HOST 0.0.0.0
+ENV NAMU_PORT 3000
+ENV NAMU_LANG ko-KR
+ENV NAMU_MARKUP namumark
+ENV NAMU_ENCRYPT sha3
+ENV NAMU_DOCKER O
+
+ADD . /app
+WORKDIR /app
+
+RUN pip install -r requirements.txt
+EXPOSE 3000
+
+CMD [ "python", "./app.py" ]

+ 21 - 0
Dockerfile.ko

@@ -0,0 +1,21 @@
+FROM python:3.10.5-alpine
+
+MAINTAINER 2du <min08101@naver.com>
+MAINTAINER hoparkgo9ma <me@ho9.me>
+
+ENV NAMU_DB_TYPE sqlite
+ENV NAMU_DB data
+ENV NAMU_HOST 0.0.0.0
+ENV NAMU_PORT 3000
+ENV NAMU_LANG ko-KR
+ENV NAMU_MARKUP namumark
+ENV NAMU_ENCRYPT sha3
+ENV NAMU_DOCKER O
+
+ADD . /app
+WORKDIR /app
+
+RUN pip install -r requirements.txt
+EXPOSE 3000
+
+CMD [ "python", "./app.py" ]

+ 254 - 179
app.py

@@ -35,162 +35,231 @@ data_db_set = class_check_json()
 
 db_data_get(data_db_set['type'])
 do_db_set(data_db_set)
-load_db = get_db_connect_old(data_db_set)
-
-conn = load_db.db_load()
-curs = conn.cursor()
-
-setup_tool = ''
-try:
-    curs.execute(db_change('select data from other where name = "ver"'))
-except:
-    setup_tool = 'init'
-
-if setup_tool != 'init':
-    ver_set_data = curs.fetchall()
-    if ver_set_data:
-        if int(version_list['beta']['c_ver']) > int(ver_set_data[0][0]):
-            setup_tool = 'update'
-        else:
-            setup_tool = 'normal'
-    else:
+
+with get_db_connect() as conn:
+    curs = conn.cursor()
+
+    setup_tool = ''
+    try:
+        curs.execute(db_change('select data from other where name = "ver"'))
+    except:
         setup_tool = 'init'
 
-if setup_tool != 'normal':
-    create_data = get_db_table_list()
-    for create_table in create_data:
-        for create in ['test'] + create_data[create_table]:
+    if setup_tool != 'init':
+        ver_set_data = curs.fetchall()
+        if ver_set_data:
+            if int(version_list['beta']['c_ver']) > int(ver_set_data[0][0]):
+                setup_tool = 'update'
+            else:
+                setup_tool = 'normal'
+        else:
+            setup_tool = 'init'
+
+    if data_db_set['type'] == 'mysql':
+        try:
+            curs.execute(db_change(
+                'create database ' + data_db_set['name'] + ' ' + \
+                'default character set utf8mb4'
+            ))
+        except:
             try:
-                curs.execute(db_change('select ' + create + ' from ' + create_table + ' limit 1'))
+                curs.execute(db_change(
+                    'alter database ' + data_db_set['name'] + ' ' + \
+                    'character set utf8mb4'
+                ))
             except:
+                pass
+
+    if setup_tool != 'normal':
+        create_data = get_db_table_list()
+        for create_table in create_data:
+            for create in ['test'] + create_data[create_table]:
+                db_pass = 0
+
                 try:
-                    curs.execute(db_change('create table ' + create_table + '(test longtext default "")'))
+                    curs.execute(db_change('select ' + create + ' from ' + create_table + ' limit 1'))
+
+                    db_pass = 1
                 except:
-                    curs.execute(db_change("alter table " + create_table + " add column " + create + " longtext default ''"))
-
-    if setup_tool == 'update':
-        update(int(ver_set_data[0][0]), set_data)
-    else:
-        set_init()
-
-set_init_always(version_list['beta']['c_ver'])
-
-# Init-Route
-class EverythingConverter(werkzeug.routing.PathConverter):
-    regex = r'.*?'
-
-class RegexConverter(werkzeug.routing.BaseConverter):
-    def __init__(self, url_map, *items):
-        super(RegexConverter, self).__init__(url_map)
-        self.regex = items[0]
-
-app = flask.Flask(
-    __name__, 
-    template_folder = './'
-)
-
-app.config['JSON_AS_ASCII'] = False
-app.config['JSONIFY_PRETTYPRINT_REGULAR'] = True
-
-log = logging.getLogger('waitress')
-log.setLevel(logging.ERROR)
-
-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
-app.url_map.converters['regex'] = RegexConverter
-
-curs.execute(db_change('select data from other where name = "key"'))
-sql_data = curs.fetchall()
-app.secret_key = sql_data[0][0]
-
-print('----')
-
-# Init-DB_Data
-server_set = {}
-server_set_var = get_init_set_list()
-server_set_env = {
-    'host' : os.getenv('NAMU_HOST'),
-    'port' : os.getenv('NAMU_PORT'),
-    'language' : os.getenv('NAMU_LANG'),
-    'markup' : os.getenv('NAMU_MARKUP'),
-    'encode' : os.getenv('NAMU_ENCRYPT')
-}
-for i in server_set_var:
-    curs.execute(db_change('select data from other where name = ?'), [i])
-    server_set_val = curs.fetchall()
-    if server_set_val:
-        server_set_val = server_set_val[0][0]
-    elif server_set_env[i] != None:
-        server_set_val = server_set_env[i]
-    else:
-        if 'list' in server_set_var[i]:
-            print(server_set_var[i]['display'] + ' (' + server_set_var[i]['default'] + ') [' + ', '.join(server_set_var[i]['list']) + ']' + ' : ', end = '')
-        else:
-            print(server_set_var[i]['display'] + ' (' + server_set_var[i]['default'] + ') : ', end = '')
+                    pass
 
-        server_set_val = input()
-        if server_set_val == '':
-            server_set_val = server_set_var[i]['default']
-        elif server_set_var[i]['require'] == 'select':
-            if not server_set_val in server_set_var[i]['list']:
-                server_set_val = server_set_var[i]['default']
+                if db_pass == 0:
+                    try:
+                        curs.execute(db_change('create table ' + create_table + '(test longtext default (""))'))
 
-        curs.execute(db_change('insert into other (name, data) values (?, ?)'), [i, server_set_val])
+                        db_pass = 1
+                    except:
+                        pass
 
-    print(server_set_var[i]['display'] + ' : ' + server_set_val)
+                if db_pass == 0:
+                    try:
+                        curs.execute(db_change('create table ' + create_table + '(test longtext default "")'))
 
-    server_set[i] = server_set_val
+                        db_pass = 1
+                    except:
+                        pass
 
-print('----')
+                if db_pass == 0:
+                    try:
+                        curs.execute(db_change('create table ' + create_table + '(test longtext)'))
 
-# Init-DB_care
-if data_db_set['type'] == 'sqlite':
-    def back_up(back_time, back_up_where):
-        print('----')
+                        db_pass = 1
+                    except:
+                        pass
 
-        try:
-            shutil.copyfile(
-                data_db_set['name'] + '.db', 
-                back_up_where
-            )
+                if db_pass == 0:
+                    try:
+                        curs.execute(db_change("alter table " + create_table + " add column " + create + " longtext default ('')"))
 
-            print('Back up : OK')
-        except:
-            print('Back up : Error')
-
-        threading.Timer(
-            60 * 60 * back_time, 
-            back_up,
-            [back_time, back_up_where]
-        ).start()
-
-    curs.execute(db_change('select data from other where name = "back_up"'))
-    back_time = curs.fetchall()
-    back_time = int(number_check(back_time[0][0])) if back_time else 0
-    if back_time != 0:
-        curs.execute(db_change('select data from other where name = "backup_where"'))
-        back_up_where = curs.fetchall()
-        if back_up_where and back_up_where[0][0] != '':
-            back_up_where = back_up_where[0][0]
+                        db_pass = 1
+                    except:
+                        pass
+
+                if db_pass == 0:
+                    try:
+                        curs.execute(db_change("alter table " + create_table + " add column " + create + " longtext default ''"))
+
+                        db_pass = 1
+                    except:
+                        pass
+
+                if db_pass == 0:
+                    try:
+                        curs.execute(db_change("alter table " + create_table + " add column " + create + " longtext"))
+
+                        db_pass = 1
+                    except:
+                        pass
+
+                if db_pass == 0:
+                    raise
+
+        if setup_tool == 'update':
+            update(int(ver_set_data[0][0]), set_data)
+        else:
+            set_init()
+
+    set_init_always(version_list['beta']['c_ver'])
+
+    # Init-Route
+    class EverythingConverter(werkzeug.routing.PathConverter):
+        regex = r'.*?'
+
+    class RegexConverter(werkzeug.routing.BaseConverter):
+        def __init__(self, url_map, *items):
+            super(RegexConverter, self).__init__(url_map)
+            self.regex = items[0]
+
+    app = flask.Flask(
+        __name__, 
+        template_folder = './'
+    )
+
+    app.config['JSON_AS_ASCII'] = False
+    app.config['JSONIFY_PRETTYPRINT_REGULAR'] = True
+
+    log = logging.getLogger('waitress')
+    log.setLevel(logging.ERROR)
+
+    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
+    app.url_map.converters['regex'] = RegexConverter
+
+    curs.execute(db_change('select data from other where name = "key"'))
+    sql_data = curs.fetchall()
+    app.secret_key = sql_data[0][0]
+
+    print('----')
+
+    # Init-DB_Data
+    server_set = {}
+    server_set_var = get_init_set_list()
+    server_set_env = {
+        'host' : os.getenv('NAMU_HOST'),
+        'port' : os.getenv('NAMU_PORT'),
+        'language' : os.getenv('NAMU_LANG'),
+        'markup' : os.getenv('NAMU_MARKUP'),
+        'encode' : os.getenv('NAMU_ENCRYPT')
+    }
+    for i in server_set_var:
+        curs.execute(db_change('select data from other where name = ?'), [i])
+        server_set_val = curs.fetchall()
+        if server_set_val:
+            server_set_val = server_set_val[0][0]
+        elif server_set_env[i] != None:
+            server_set_val = server_set_env[i]
+
+            curs.execute(db_change('insert into other (name, data) values (?, ?)'), [i, server_set_env[i]])
         else:
-            back_up_where = 'back_' + data_db_set['name'] + '.db'
+            if 'list' in server_set_var[i]:
+                print(server_set_var[i]['display'] + ' (' + server_set_var[i]['default'] + ') [' + ', '.join(server_set_var[i]['list']) + ']' + ' : ', end = '')
+            else:
+                print(server_set_var[i]['display'] + ' (' + server_set_var[i]['default'] + ') : ', end = '')
+
+            server_set_val = input()
+            if server_set_val == '':
+                server_set_val = server_set_var[i]['default']
+            elif server_set_var[i]['require'] == 'select':
+                if not server_set_val in server_set_var[i]['list']:
+                    server_set_val = server_set_var[i]['default']
+
+            curs.execute(db_change('insert into other (name, data) values (?, ?)'), [i, server_set_val])
+
+        print(server_set_var[i]['display'] + ' : ' + server_set_val)
 
-        print('Back up state : ' + str(back_time) + ' hours')
+        server_set[i] = server_set_val
 
-        back_up(back_time, back_up_where)
-    else:
-        print('Back up state : Turn off')
+    print('----')
 
-print('Now running... http://localhost:' + server_set['port'])
-conn.commit()
+    # Init-DB_care
+    if data_db_set['type'] == 'sqlite':
+        def back_up(back_time, back_up_where):
+            print('----')
+
+            try:
+                shutil.copyfile(
+                    data_db_set['name'] + '.db', 
+                    back_up_where
+                )
+
+                print('Back up : OK')
+            except:
+                print('Back up : Error')
+
+            threading.Timer(
+                60 * 60 * back_time, 
+                back_up,
+                [back_time, back_up_where]
+            ).start()
+
+        curs.execute(db_change('select data from other where name = "back_up"'))
+        back_time = curs.fetchall()
+        back_time = int(number_check(back_time[0][0])) if back_time and back_time != '' else 0
+        if back_time != 0:
+            curs.execute(db_change('select data from other where name = "backup_where"'))
+            back_up_where = curs.fetchall()
+            if back_up_where and back_up_where[0][0] != '':
+                back_up_where = back_up_where[0][0]
+            else:
+                back_up_where = 'back_' + data_db_set['name'] + '.db'
+
+            print('Back up state : ' + str(back_time) + ' hours')
+
+            back_up(back_time, back_up_where)
+        else:
+            print('Back up state : Turn off')
+
+    print('Now running... http://localhost:' + server_set['port'])
+    
+    conn.commit()
 
 # Init-custom
 if os.path.exists('custom.py'):
     from custom import custom_run
-    custom_run(load_db.db_get(), app)
+    custom_run('error', app)
     
 # Func
 # Func-inter_wiki
@@ -240,96 +309,96 @@ app.route('/old_page')(list_old_page)
 # /list/document/acl
 @app.route('/acl_list')
 def list_acl():
-    return list_acl_2(load_db.db_get())
+    return list_acl_2()
 
 # /list/document/acl/add
 @app.route('/acl/<everything:name>', methods = ['POST', 'GET'])
 def give_acl(name = None):
-    return give_acl_2(load_db.db_get(), name)
+    return give_acl_2(name)
 
 # /list/document/need
 @app.route('/please')
 def list_please():
-    return list_please_2(load_db.db_get())
+    return list_please_2()
 
 # /list/document/all
 @app.route('/title_index')
 def list_title_index():
-    return list_title_index_2(load_db.db_get())
+    return list_title_index_2()
 
 # /list/document/long
 @app.route('/long_page')
 def list_long_page():
-    return list_long_page_2(load_db.db_get(), 'long_page')
+    return list_long_page_2('long_page')
 
 # /list/document/short
 @app.route('/short_page')
 def list_short_page():
-    return list_long_page_2(load_db.db_get(), 'short_page')
+    return list_long_page_2('short_page')
 
 # /list/file
 @app.route('/image_file_list')
 def list_image_file():
-    return list_image_file_2(load_db.db_get())
+    return list_image_file_2()
 
 # /list/admin
 # /list/admin/list
 @app.route('/admin_list')
 def list_admin():
-    return list_admin_2(load_db.db_get())
+    return list_admin_2()
 
 # /list/admin/auth_use
 @app.route('/admin_log', methods = ['POST', 'GET'])
 def list_admin_use():
-    return list_admin_use_2(load_db.db_get())
+    return list_admin_use_2()
 
 # /list/user
 @app.route('/user_log')
 def list_user():
-    return list_user_2(load_db.db_get())
+    return list_user_2()
 
 # /list/user/check
 @app.route('/check/<name>')
 def give_user_check(name = None):
-    return give_user_check_2(load_db.db_get(), name)
+    return give_user_check_2(name)
     
 # /list/user/check/delete
 @app.route('/check_delete', methods = ['POST', 'GET'])
 def give_user_check_delete():
-    return give_user_check_delete_2(load_db.db_get())
+    return give_user_check_delete_2()
 
 # Func-auth
 # /auth/give
 # /auth/give/<name>
 @app.route('/admin/<name>', methods = ['POST', 'GET'])
 def give_admin(name = None):
-    return give_admin_2(load_db.db_get(), name)
+    return give_admin_2(name)
 
 # /auth/give
 # /auth/give/<name>
-@app.route('/ban', methods = ['POST', 'GET'])
-@app.route('/ban/<name>', methods = ['POST', 'GET'])
-def give_user_ban(name = None):
-    return give_user_ban_2(load_db.db_get(), name)
+app.route('/auth/give/ban', methods = ['POST', 'GET'])(give_user_ban)
+app.route('/auth/give/ban/<name>', methods = ['POST', 'GET'])(give_user_ban)
+app.route('/auth/give/ban_regex/<everything:name>', methods = ['POST', 'GET'], defaults = { 'ban_type' : 'regex' })(give_user_ban)
+app.route('/auth/give/ban_multiple', methods = ['POST', 'GET'], defaults = { 'ban_type' : 'multiple' })(give_user_ban)
 
 # /auth/list
 @app.route('/admin_group')
 def list_admin_group():
-    return list_admin_group_2(load_db.db_get())
+    return list_admin_group_2()
 
 # /auth/list/add/<name>
 @app.route('/admin_plus/<name>', methods = ['POST', 'GET'])
 def give_admin_groups(name = None):
-    return give_admin_groups_2(load_db.db_get(), name)
+    return give_admin_groups_2(name)
 
 # /auth/list/delete/<name>
 @app.route('/delete_admin_group/<name>', methods = ['POST', 'GET'])
 def give_delete_admin_group(name = None):
-    return give_delete_admin_group_2(load_db.db_get(), name)
+    return give_delete_admin_group_2(name)
 
 @app.route('/app_submit', methods = ['POST', 'GET'])
 def recent_app_submit():
-    return recent_app_submit_2(load_db.db_get())
+    return recent_app_submit_2()
 
 # /auth/history
 # ongoing 반영 필요
@@ -337,7 +406,7 @@ def recent_app_submit():
 @app.route('/block_log/<regex("user"):tool>/<name>')
 @app.route('/block_log/<regex("admin"):tool>/<name>')
 def recent_block(name = 'Test', tool = 'all'):
-    return recent_block_2(load_db.db_get(), name, tool)
+    return recent_block_2(name, tool)
 
 # Func-history
 app.route('/recent_change')(recent_change)
@@ -372,21 +441,21 @@ app.route('/w_rev/<int(signed = True):doc_rev>/<everything:name>')(view_read)
 app.route('/w_from/<everything:name>', defaults = { 'do_type' : 'from' })(view_read)
 app.route('/w/<everything:name>')(view_read)
 
-app.route('/random')(main_func_random)
+app.route('/random')(view_random)
 
 # Func-edit
 app.route('/edit/<everything:name>', methods = ['POST', 'GET'])(edit)
-app.route('/edit/<everything:name>/doc_from/<everything:name_load>', methods = ['POST', 'GET'])(edit)
-app.route('/edit/<everything:name>/doc_section/<int:section>', methods = ['POST', 'GET'])(edit)
+app.route('/edit_from/<everything:name>', methods = ['POST', 'GET'], defaults = { 'do_type' : 'load' })(edit)
+app.route('/edit_section/<int:section>/<everything:name>', methods = ['POST', 'GET'])(edit)
 
-app.route('/upload', methods = ['POST', 'GET'])(main_func_upload)
+app.route('/upload', methods = ['POST', 'GET'])(edit_upload)
 
 # 개편 예정
 app.route('/xref_reset/<everything:name>')(edit_backlink_reset)
 
 app.route('/delete/<everything:name>', methods = ['POST', 'GET'])(edit_delete)
 app.route('/delete_file/<everything:name>', methods = ['POST', 'GET'])(edit_delete_file)
-app.route('/delete_mutiple', methods = ['POST', 'GET'])(edit_delete_mutiple)
+app.route('/delete_multiple', methods = ['POST', 'GET'])(edit_delete_multiple)
 
 app.route('/revert/<int:num>/<everything:name>', methods = ['POST', 'GET'])(edit_revert)
 
@@ -417,7 +486,9 @@ app.route('/change', methods = ['POST', 'GET'])(user_setting)
 app.route('/change/key')(user_setting_key)
 app.route('/change/key/delete')(user_setting_key_delete)
 app.route('/change/pw', methods = ['POST', 'GET'])(user_setting_pw)
-app.route('/change/head', methods=['GET', 'POST'])(user_setting_head)
+app.route('/change/head', methods=['GET', 'POST'], defaults = { 'skin_name' : '' })(user_setting_head)
+app.route('/change/head/<skin_name>', methods=['GET', 'POST'])(user_setting_head)
+app.route('/change/head_reset', methods=['GET', 'POST'])(user_setting_head_reset)
 app.route('/change/skin_set')(user_setting_skin_set)
 app.route('/change/skin_set/main')(user_setting_skin_set)
 
@@ -446,13 +517,13 @@ app.route('/skin_set')(user_setting_skin_set)
 # 개편 보류중 S
 @app.route('/change/email', methods = ['POST', 'GET'])
 def user_setting_email():
-    return user_setting_email_2(load_db.db_get())
+    return user_setting_email_2()
 
 app.route('/change/email/delete')(user_setting_email_delete)
 
 @app.route('/change/email/check', methods = ['POST', 'GET'])
 def user_setting_email_check():
-    return user_setting_email_check_2(load_db.db_get())
+    return user_setting_email_check_2()
 # 개편 보류중 E
 
 # Func-login
@@ -464,27 +535,27 @@ def user_setting_email_check():
 
 @app.route('/login', methods = ['POST', 'GET'])
 def login_login():
-    return login_login_2(load_db.db_get())
+    return login_login_2()
 
 @app.route('/login/2fa', methods = ['POST', 'GET'])
 def login_login_2fa():
-    return login_login_2fa_2(load_db.db_get())
+    return login_login_2fa_2()
 
 @app.route('/register', methods = ['POST', 'GET'])
 def login_register():
-    return login_register_2(load_db.db_get())
+    return login_register_2()
 
 @app.route('/register/email', methods = ['POST', 'GET'])
 def login_register_email():
-    return login_register_email_2(load_db.db_get())
+    return login_register_email_2()
 
 @app.route('/register/email/check', methods = ['POST', 'GET'])
 def login_register_email_check():
-    return login_register_email_check_2(load_db.db_get())
+    return login_register_email_check_2()
 
 @app.route('/register/submit', methods = ['POST', 'GET'])
 def login_register_submit():
-    return login_register_submit_2(load_db.db_get())
+    return login_register_submit_2()
 
 app.route('/login/find')(login_find)
 app.route('/login/find/key', methods = ['POST', 'GET'])(login_find_key)
@@ -512,13 +583,12 @@ app.route('/api/raw/<everything:name>')(api_raw)
 app.route('/api/version', defaults = { 'version_list' : version_list })(api_version)
 app.route('/api/skin_info')(api_skin_info)
 app.route('/api/skin_info/<name>')(api_skin_info)
-app.route('/api/markup')(api_markup)
 app.route('/api/user_info/<name>', methods = ['POST', 'GET'])(api_user_info)
 app.route('/api/setting/<name>')(api_setting)
 
-app.route('/api/thread/<int:topic_num>/<tool>/<int:num>')(api_topic_sub)
-app.route('/api/thread/<int:topic_num>/<tool>')(api_topic_sub)
-app.route('/api/thread/<int:topic_num>')(api_topic_sub)
+app.route('/api/thread/<int:topic_num>/<tool>/<int:num>')(api_topic)
+app.route('/api/thread/<int:topic_num>/<tool>')(api_topic)
+app.route('/api/thread/<int:topic_num>')(api_topic)
 
 app.route('/api/search/<everything:name>/doc_num/<int:num>/<int:page>')(api_search)
 app.route('/api/search/<everything:name>')(api_search)
@@ -532,21 +602,25 @@ app.route('/api/recent_discuss/<get_type>/<int:num>')(api_recent_discuss)
 app.route('/api/recent_discuss/<int:num>')(api_recent_discuss)
 app.route('/api/recent_discuss')(api_recent_discuss)
 
-app.route('/api/sha224/<everything:data>', methods = ['POST', 'GET'])(api_sha224)
+app.route('/api/lang/<data>', methods = ['POST', 'GET'])(api_func_lang)
+app.route('/api/sha224/<everything:data>', methods = ['POST', 'GET'])(api_func_sha224)
+
 app.route('/api/title_index')(api_title_index)
 app.route('/api/image/<everything:name>', methods = ['POST', 'GET'])(api_image_view)
-# 이건 API 영역이 아닌 것 같아서 고심 중
-app.route('/api/sitemap.xml')(api_sitemap)
 
 # Func-main
 # 여기도 전반적인 조정 시행 예정
 app.route('/other')(main_tool_other)
 app.route('/manager', methods = ['POST', 'GET'])(main_tool_admin)
-app.route('/manager/<int:num>', methods = ['POST', 'GET'])(main_tool_admin)
-app.route('/manager/<int:num>/<add_2>', methods = ['POST', 'GET'])(main_tool_admin)
+app.route('/manager/<int:num>', methods = ['POST', 'GET'])(main_tool_redirect)
+app.route('/manager/<int:num>/<add_2>', methods = ['POST', 'GET'])(main_tool_redirect)
+# app.route('/guide/<doc_name>')(main_tool_guide)
 
 app.route('/search', methods=['POST'])(main_search)
 app.route('/search/<everything:name>')(main_search_deep)
+app.route('/search/<int:num>/<everything:name>')(main_search_deep)
+app.route('/search_data/<everything:name>', defaults = { 'search_type' : 'data' })(main_search_deep)
+app.route('/search_data/<int:num>/<everything:name>', defaults = { 'search_type' : 'data' })(main_search_deep)
 app.route('/goto', methods=['POST'])(main_search_goto)
 app.route('/goto/<everything:name>', methods=['POST'])(main_search_goto)
 
@@ -563,6 +637,7 @@ app.route('/setting/body/bottom/<skin_name>', defaults = { 'num' : 7 }, methods
 app.route('/setting/robot', methods = ['POST', 'GET'])(main_func_setting_robot)
 app.route('/setting/external', methods = ['POST', 'GET'])(main_func_setting_external)
 app.route('/setting/acl', methods = ['POST', 'GET'])(main_func_setting_acl)
+app.route('/setting/sitemap', methods = ['POST', 'GET'])(main_func_setting_sitemap)
 
 # views -> view
 app.route('/view/<everything:name>')(main_view)

+ 42 - 3
emergency_tool.py

@@ -1,5 +1,10 @@
 # Load
 import time
+import os
+import platform
+import urllib
+import zipfile
+
 from route.tool.func import *
 
 while True:
@@ -12,9 +17,10 @@ if data_db_load == 'Y':
 
     db_data_get(data_db_set['type'])
     do_db_set(data_db_set)
-    load_db = get_db_connect_old(data_db_set)
 
-    conn = load_db.db_load()
+    load_db = get_db_connect()
+
+    conn = load_db.__enter__()
     curs = conn.cursor()
 else:
     print('----')
@@ -38,6 +44,8 @@ print('14. Delete Main <HEAD>')
 print('15. Give owner')
 print('16. Delete 2FA password')
 print('17. Change markup')
+print('18. Change wiki access password')
+print('19. Forced update')
 
 print('----')
 what_i_do = input('Select : ')
@@ -215,6 +223,37 @@ elif what_i_do == '17':
     markup = input('Markup name : ')
 
     curs.execute(db_change("update other set data = ? where name = 'markup'"), [markup])
+elif what_i_do == '18':
+    print('----')
+    wiki_access_password = input('Password : ')
+
+    curs.execute(db_change("update other set data = ? where name = 'wiki_access_password'"), [wiki_access_password])
+elif what_i_do == '19':
+    print('----')
+    up_data = input('Insert branch (beta) [stable, beta, dev] : ')
+
+    if not up_data in ['stable', 'beta', 'dev']:
+        up_data = 'beta'
+
+    if platform.system() == 'Linux':
+        ok = []
+
+        ok += [os.system('git remote rm origin')]
+        ok += [os.system('git remote add origin https://github.com/opennamu/opennamu.git')]
+        ok += [os.system('git fetch origin ' + up_data)]
+        ok += [os.system('git reset --hard origin/' + up_data)]
+        if (ok[0] and ok[1] and ok[2] and ok[3]) != 0:
+            print('Error : update failed')
+    elif platform.system() == 'Windows':
+        os.system('rd /s /q route')
+        urllib.request.urlretrieve('https://github.com/opennamu/opennamu/archive/' + up_data + '.zip', 'update.zip')
+        zipfile.ZipFile('update.zip').extractall('')
+        ok = os.system('xcopy /y /s /r opennamu-' + up_data + ' .')
+        if ok == 0:
+            os.system('rd /s /q opennamu-' + up_data)
+            os.system('del update.zip')
+        else:
+            print('Error : update failed')
 else:
     raise ValueError(what_i_do)
 
@@ -222,4 +261,4 @@ if data_db_load == 'Y':
     conn.commit()
 
 print('----')
-print('OK')
+print('OK')

+ 67 - 16
lang/en-US.json

@@ -54,7 +54,6 @@
         "open" : "Open",
         "agreement" : "Agreement",
         "template" : "Template",
-        "category" : "Category",
         "file" : "File",
         "writer" : "Writer",
         "editor" : "Editor",
@@ -109,6 +108,7 @@
         "alpha" : "Alpha",
         "beta" : "Beta",
         "example" : "Example",
+        "reset" : "Reset",
         "_comment_1.1_" : "Time",
             "second" : "Second(s)",
             "hour" : "Hour(s)",
@@ -137,7 +137,6 @@
         "recent_change" : "Recently edit(s)",
         "edit_filter" : "Contents filter",
         "recent_ban" : "Block(s) record",
-        "load" : "Load another document",
         "edit_filter_rule" : "Contents filter rule",
         "move_history" : "History of moveing",
         "other_tool" : "Other tools",
@@ -194,7 +193,7 @@
         "accept_edit_request" : "Accept edit request",
         "history_add" : "Add history",
         "all_register_num" : "The number of application forms",
-        "replace_move" : "Swaping documents",
+        "replace_move" : "Interchange",
         "merge_move" : "Merging documents",
         "add_admin_group" : "Add administrator groups",
         "add_watchlist" : "Add watchlist",
@@ -210,7 +209,6 @@
         "link_in_this" : "Links in this document",
         "star_doc" : "Document(s) of interest",
         "add_star_doc" : "Add document(s) of interest",
-        "get_sitemap" : "Create or renewal sitemap.xml",
         "simple_check" : "Simple check",
         "add_user" : "Add user",
         "2fa" : "2FA",
@@ -226,6 +224,18 @@
         "email_delete" : "Delete email",
         "challenge" : "Challenge",
         "user_title" : "User title",
+        "multiple_ban" : "Multiple ban",
+    	"dont_move" : "Don't move",
+        "file_delete" : "File delete",
+        "_comment_" : "Edit",
+            "load" : "Load another document",
+            "turn_off_monaco" : "Turn off monaco editor",
+        "_comment_" : "Render",
+            "toc" : "TOC",
+            "category" : "Category",
+        "_comment_" : "Search",
+            "search_document_name" : "Search document name",
+            "search_document_data" : "Search document data",
         "_comment_2.1_" : "Filter",
             "_comment_2.1.1_" : "List",
                 "interwiki_list" : "Interwiki(s) list",
@@ -295,6 +305,10 @@
                 "tls_method" : "TLS method",
                 "title_max_length" : "Documents title maximum length",
                 "title_topic_max_length" : "Discussions topic maximum length",
+                "password_min_length" : "Password minimum length",
+                "set_wiki_access_password_need" : "Password required for wiki access",
+                "set_wiki_access_password" : "Wiki access password",
+                "set_history_recording_off" : "Stop recording history",
             "_comment_2.2.3_" : "Text",
                 "register_text" : "Terms of sign-up",
                 "non_login_alert" : "Non-login alert",
@@ -312,6 +326,9 @@
                 "upload_help" : "File upload phrase",
                 "upload_default" : "File upload other Default",
                 "topic_text" : "Discussion textarea phrase",
+                "phrase_user_page_admin" : "Administrator user page phrase",
+                "phrase_user_page_owner" : "Onwer user page phrase",
+                "phrase_old_page_warring" : "Warning on previous revision document visit",
             "_comment_2.2.4_" : "Ext_API",
                 "recaptcha" : "reCAPTCHA",
                 "hcaptcha" : "hCAPTCHA",
@@ -329,6 +346,12 @@
                 "oauth" : "OAuth",
                 "_comment_2.2.4.2_" : "OAuth",
                     "oauth_client_id" : "OAuth client ID",
+            "_comment_" : "Sitemap",
+                "sitemap_management" : "sitemap.xml management",
+                "stiemap_exclude_domain" : "Exclude domain",
+                "stiemap_exclude_user_page" : "Exclude user page(s)",
+                "stiemap_exclude_file_page" : "Exclude file page(s)",
+                "stiemap_exclude_category_page" : "Exclude category page(s)",
         "_comment_2.3_" : "List",
             "open_discussion_list" : "Open discussion(s) list",
             "discussion_list" : "Discussion(s) list",
@@ -360,6 +383,23 @@
             "topic_tool" : "Discussion management tools",
             "topic_state" : "Discussion status",
             "topic_delete" : "Delete this thread",
+            "topic_view_acl" : "Discussion View ACL",
+            "topic_normal" : "Normal",
+            "topic_stop" : "Stop",
+            "topic_close" : "Close",
+            "topic_agree" : "Discussion Agreed",
+            "_comment_" : "Topic set",
+                "topic_change_agree" : "Transition to a consensus discussion",
+                "topic_progress" : "Discussion progress",
+                "topic_associate" : "Associate discussion with other features",
+                "topic_link_vote" : "Link votes to discussion",
+                "topic_insert_vote_number" : "Number of the vote",
+                "_comment_" : "Topic state",
+                    "topic_state_change_normal" : "The admin normalized the discussion.",
+                    "topic_state_change_stop" : "The admin has stopped the discussion.",
+                    "topic_state_change_close" : "The admin has closed the discussion.",
+                    "topic_state_change_agree" : "The admin has approved the discussion agreement.",
+                    "topic_state_change_disagree" : "The admin has broken the agreement of the discussion.",
         "_comment_2.5_" : "Period",
             "1_day" : "1 day",
             "5_day" : "5 days",
@@ -367,19 +407,25 @@
             "180_day" : "180 days",
             "360_day" : "360 days",
         "_comment_2.6_" : "ACL",
-            "admin_acl" : "Administrators only",
-            "member_acl" : "Members only",
-            "50_edit_acl" : "Only members with 50 or more document edits",
-            "all_acl" : "All users",
-            "email_acl" : "Only users with email",
-            "owner_acl" : "Owner only",
-            "before_acl" : "Only those who have edited this document before",
-            "ban_acl" : "Include blocked users",
-            "ban_admin_acl" : "Blocked users and administrators",
-            "30_day_acl" : "Only members 30 days after sign up",
-            "_comment_2.6_1_" : "Set",
+            "_comment_" : "Set data",
+                "admin_acl" : "Administrators, owners",
+                "member_acl" : "Members",
+                "50_edit_acl" : "Members with 50 or more document edits, administrators, owners",
+                "all_acl" : "All users exclude blocked users",
+                "email_acl" : "Members with email, administrators, owners",
+                "owner_acl" : "Owners",
+                "before_acl" : "Those who have edited this document before, administrators, owners",
+                "ban_acl" : "All users include blocked users",
+                "ban_admin_acl" : "Blocked users, administrators, owners",
+                "30_day_acl" : "Members 30 days after sign up, administrators, owners",
+                "not_all_acl" : "All prohibited",
+            "_comment_" : "Set name",
                 "document_acl" : "Document ACL",
+                "document_edit_acl" : "Document edit ACL",
+                "document_move_acl" : "Document move ACL",
+                "document_delete_acl" : "Document delete ACL",
                 "discussion_acl" : "Discussion(s) ACL",
+                "thread_acl" : "Thread ACL",
                 "view_acl" : "Reading ACL",
                 "user_document_acl" : "User document ACL",
                 "upload_acl" : "Upload ACL",
@@ -415,6 +461,7 @@
         "default_edit_help" : "Describe it here",
         "markup_enabled" : "Markup enabled",
         "many_delete_help" : "Please write down the documents name one by one on the line.",
+        "name_or_ip_or_regex_multiple" : "Please write down the username or IP or Regex 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",
         "msg_whatchlist_lmt": "You can add as many as",
@@ -441,7 +488,7 @@
             "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): ",
-            "decument_exist_error" : "The document with that title already exists.",
+            "move_error" : "An error occurred while moving. All or part of it has not been moved.",
             "password_diffrent_error" : "Reconfirm password and input password are different.",
             "edit_filter_error" : "Censored by edit filter.",
             "file_name_error" : "Only English alphabets, Korean alphabets, spaces, underscore, and hyphens are allowed for the file name.",
@@ -461,12 +508,16 @@
             "input_email_error" : "There is a problem with the input value.",
             "error_edit_send_request" : "Entering a reason is required.",
             "error_title_length_too_long" : "Documents title or Discussion topic length is too long. Maximum number of characters : ",
+            "error_password_length_too_short" : "Password length is too short. Minimum number of characters : ",
+            "error_password_require_for_wiki_access" : "A password is required to access the wiki.",
         "_comment_3.2_" : "Warning",
             "http_warning" : "Warning: If you are not on HTTPS connection, your information can be leaked. The users themselves have responsibility to any problems that happen because of this.",
             "user_head_warning" : "User data will be deleted if you close the browser or when you sign in.",
             "no_login_warning" : "You are not logged in. Your current IP address will be logged within editing or discussing until you log in.",
             "update_warning" : "Manual updates are recommended if your version is 0.2 or lower than the latest version. For Windows, the contents of the route folder will be deleted.",
             "history_delete_warning" : "If you erase history, it's hard to restore it, so please be careful.",
+            "user_css_warning" : "If you have a problem using this, connect here.",
+            "main_css_warning" : "If you have a problem using this, use the emergency tool.",
         "_comment_" : "Challenge",
             "challenge_title_register" : "Hello, World!",
             "challenge_info_register" : "Sign up",

+ 58 - 14
lang/ko-KR.json

@@ -46,7 +46,6 @@
     "state": "상태",
     "authorize": "권한 부여",
     "check_user": "사용자 검사",
-    "email_acl": "이메일 인증을 받은 사용자만",
     "email_error": "해당 이메일을 가진 사용자가 존재하지 않습니다.",
     "version": "버전",
     "open": "열기",
@@ -64,7 +63,6 @@
     "no_login_error": "비로그인 상태입니다.",
     "upload": "파일 올리기",
     "user_name": "사용자 이름",
-    "member_acl": "가입자만",
     "search": "검색",
     "etc": "기타",
     "edit_filter": "편집 필터",
@@ -81,7 +79,6 @@
     "password_diffrent_error": "입력한 비밀번호와 비밀번호 확인이 서로 다릅니다.",
     "180_day": "180일",
     "markup_enabled": "문법 사용 가능",
-    "all_acl": "모든 사용자",
     "send": "전송",
     "not_sure": "확실하지 않음",
     "file_name_error": "파일명에는 알파벳, 한글, 공백, 밑줄 및 빼기 기호만 사용할 수 있습니다.",
@@ -145,7 +142,6 @@
     "host": "호스트",
     "email_text": "이메일 내용",
     "recent": "최근",
-    "admin_acl": "관리자만",
     "wiki_host": "위키 호스트",
     "error_404": "존재하지 않는 문서 문구",
     "member_list": "사용자 목록",
@@ -171,7 +167,7 @@
     "copyright_checkbox_text": "저작권 동의 문구(체크박스 형태)",
     "authority": "권한",
     "document": "문서",
-    "decument_exist_error": "이동하려는 문서에 이미 문서가 존재합니다.",
+    "move_error": "이동하는 과정 중 오류가 발생하였습니다. 전부 또는 일부가 이동되지 않았습니다.",
     "skin_setting": "스킨 설정",
     "discussion_list": "토론 목록",
     "restart_required": "재시작 필요",
@@ -274,7 +270,6 @@
     "hide_release": "숨김 해제",
     "360_day": "360일",
     "inter_error": "내부 오류.",
-    "50_edit_acl": "기여 횟수가 50회 이상인 가입자만",
     "tool": "도구",
     "adsense_enable": "애드센스 사용",
     "list": "목록",
@@ -291,7 +286,6 @@
     "acl_record": "ACL 기록",
     "main_bottom_body": "본문 하단",
     "reference": "참고",
-    "owner_acl": "소유자만",
     "last_edit_time": "최근 수정 시각",
     "link": "링크",
     "icon": "아이콘",
@@ -329,7 +323,7 @@
     "application_not_found": "존재하지 않는 회원가입 신청입니다.",
     "approval_requirement_disabled": "현재 가입시 승인필요 설정이 비활성화되어있습니다. 필요시 설정에서 활성화할 수 있습니다.",
     "all_register_num": "모든 가입 신청자의 수",
-    "replace_move": "서 바꾸기",
+    "replace_move": "서 바꾸기",
     "merge_move": "문서 병합",
     "add_admin_group": "관리자 그룹 추가",
     "add_watchlist": "주시 문서 추가",
@@ -345,8 +339,6 @@
     "extension_filter_list": "확장자 필터 목록",
     "extension_filter_add": "확장자 필터 추가",
     "extension": "확장자",
-    "ban_acl": "차단된 사용자 포함",
-    "ban_admin_acl": "차단된 사용자 및 관리자",
     "topic_name_change": "토론 제목 변경",
     "topic_acl_setting": "토론 ACL 설정",
     "topic_acl": "토론 ACL",
@@ -362,12 +354,10 @@
     "backup_where": "백업 위치",
     "empty": "빈칸",
     "email_send_error": "이메일 전송이 실패했습니다.",
-    "get_sitemap": "sitemap.xml 만들거나 갱신하기",
+    "sitemap_management": "sitemap.xml 관리",
     "same_ip_exist": "동일한 아이피가 존재합니다.",
     "restart_fail_error": "재시작이 실패했습니다. 수동 재시작을 이용해주세요.",
     "domain": "도메인",
-    "before_acl": "이 문서를 이전에 편집한 적 있는 사람만",
-    "30_day_acl": "가입 후 30일이 지난 가입자만",
     "simple_check": "간편 검사",
     "add_user": "계정 추가",
     "result": "결과",
@@ -443,5 +433,59 @@
     "tls_method": "TLS 방식",
     "title_max_length": "문서 제목 최대 길이",
     "title_topic_max_length": "토론 제목 최대 길이",
-    "error_title_length_too_long": "문서 제목이나 토론 제목의 길이가 너무 깁니다. 최대 글자 수 : "
+    "error_title_length_too_long": "문서 제목이나 토론 제목의 길이가 너무 깁니다. 최대 글자 수 : ",
+    "thread_acl": "스레드 ACL",
+    "password_min_length": "비밀번호 최소 길이",
+    "error_password_length_too_short": "비밀번호 길이가 너무 짧습니다. 최소 글자 수 : ",
+    "phrase_user_page_admin": "관리자인 사용자 문서 문구",
+    "phrase_user_page_owner": "소유자인 사용자 문서 문구",
+    "error_password_require_for_wiki_access": "위키에 접속하려면 비밀번호가 필요합니다.",
+    "set_wiki_access_password_need": "위키 접속시 비밀번호 필요",
+    "set_wiki_access_password": "위키 접속 비밀번호",
+    "set_history_recording_off": "역사 기록 중지",
+    "multiple_ban": "다중 차단",
+    "name_or_ip_or_regex_multiple": "한 줄에 IP나 정규식을 한 개씩 적어주세요.",
+    "dont_move": "이동하지 않음",
+    "stiemap_exclude_domain": "도메인 제외",
+    "stiemap_exclude_user_page": "사용자 문서 제외",
+    "stiemap_exclude_file_page": "파일 문서 제외",
+    "stiemap_exclude_category_page": "분류 문서 제외",
+    "search_document_name": "문서명 검색",
+    "search_document_data": "문서 내용 검색",
+    "admin_acl": "관리자, 소유자",
+    "member_acl": "가입자",
+    "50_edit_acl": "기여 횟수가 50회 이상인 가입자, 관리자, 소유자",
+    "all_acl": "전체 사용자 (차단자 제외)",
+    "email_acl": "이메일을 등록한 가입자, 관리자, 소유자",
+    "owner_acl": "소유자",
+    "before_acl": "전에 이 문서를 편집한 적 있는 사람, 관리자, 가입자",
+    "ban_acl": "전체 사용자 (차단자 포함)",
+    "ban_admin_acl": "차단자, 관리자, 소유자",
+    "30_day_acl": "가입 후 30일이 지난 가입자, 관리자, 소유자",
+    "not_all_acl": "전부 금지",
+    "document_move_acl": "문서 이동 ACL",
+    "document_delete_acl": "문서 삭제 ACL",
+    "document_edit_acl": "문서 편집 ACL",
+    "phrase_old_page_warring": "이전 리비전 문서 방문시 경고문",
+    "toc": "목차",
+    "topic_view_acl": "토론 보기 ACL",
+    "file_delete": "파일 삭제",
+    "topic_change_agree": "합의가 완료된 토론으로 전환",
+    "topic_progress": "토론 진행",
+    "topic_associate": "다른 기능과 토론 연계",
+    "topic_link_vote": "토론과 투표 연계",
+    "topic_insert_vote_number": "투표의 번호",
+    "topic_state_change_normal": "관리자가 토론을 정상화 했습니다.",
+    "topic_state_change_stop": "관리자가 토론을 중지 했습니다.",
+    "topic_state_change_close": "관리자가 토론을 닫았습니다.",
+    "topic_state_change_agree": "관리자가 토론의 합의를 승인했습니다.",
+    "topic_state_change_disagree": "관리자가 토론의 합의를 파기했습니다.",
+    "topic_normal": "일반",
+    "topic_stop": "중지",
+    "topic_close": "닫힘",
+    "turn_off_monaco": "모나코 에디터 끄기",
+    "topic_agree": "토론 합의 완료",
+    "user_css_warning": "만약 사용하다가 문제가 생기면 여기로 접속하세요.",
+    "main_css_warning": "만약 사용하다가 문제가 생기면 이머전시 툴을 사용하세요.",
+    "reset" : "초기화"
 }

+ 18 - 0
route/api_func_lang.py

@@ -0,0 +1,18 @@
+from .tool.func import *
+
+def api_func_lang(data = 'Test'):
+    with get_db_connect() as conn:
+        if flask.request.method == 'POST':
+            try:
+                title_list = json.loads(flask.request.form.get('title_list', ''))
+                title_list = list(set(title_list))
+            except:
+                title_list = []
+
+            data_list = {}
+            for i in title_list:
+                data_list[i] = load_lang(i)
+
+            return flask.jsonify(data_list)
+        else:
+            return flask.jsonify({ "data" : load_lang(data) })

+ 18 - 0
route/api_func_sha224.py

@@ -0,0 +1,18 @@
+from .tool.func import *
+
+def api_func_sha224(data = 'Test'):
+    with get_db_connect() as conn:
+        if flask.request.method == 'POST':
+            try:
+                title_list = json.loads(flask.request.form.get('title_list', ''))
+                title_list = list(set(title_list))
+            except:
+                title_list = []
+
+            data_list = {}
+            for i in title_list:
+                data_list[i] = sha224_replace(i)
+
+            return flask.jsonify(data_list)
+        else:
+            return flask.jsonify({ "data" : sha224_replace(data) })

+ 18 - 17
route/api_image_view.py

@@ -1,21 +1,22 @@
 from .tool.func import *
 
 def api_image_view(name = 'Test'):
-    if flask.request.method == 'POST':
-        try:
-            title_list = json.loads(flask.request.form.get('title_list', ''))
-            title_list = list(set(title_list))
-        except:
-            title_list = []
-        
-        data_list = {}
-        for i in title_list:
-            if os.path.exists(os.path.join(load_image_url(), i)):
-                data_list[i] = '1'
-        
-        return flask.jsonify(data_list)
-    else:
-        if os.path.exists(os.path.join(load_image_url(), name)):
-            return flask.jsonify({ "exist" : "1" })
+    with get_db_connect() as conn:
+        if flask.request.method == 'POST':
+            try:
+                title_list = json.loads(flask.request.form.get('title_list', ''))
+                title_list = list(set(title_list))
+            except:
+                title_list = []
+
+            data_list = {}
+            for i in title_list:
+                if os.path.exists(os.path.join(load_image_url(), i)):
+                    data_list[i] = '1'
+
+            return flask.jsonify(data_list)
         else:
-            return flask.jsonify({})
+            if os.path.exists(os.path.join(load_image_url(), name)):
+                return flask.jsonify({ "exist" : "1" })
+            else:
+                return flask.jsonify({})

+ 0 - 12
route/api_markup.py

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

+ 0 - 17
route/api_sha224.py

@@ -1,17 +0,0 @@
-from .tool.func import *
-
-def api_sha224(data = 'Test'):
-    if flask.request.method == 'POST':
-        try:
-            title_list = json.loads(flask.request.form.get('title_list', ''))
-            title_list = list(set(title_list))
-        except:
-            title_list = []
-
-        data_list = {}
-        for i in title_list:
-            data_list[i] = sha224_replace(i)
-
-        return flask.jsonify(data_list)
-    else:
-        return flask.jsonify({ "data" : sha224_replace(data) })

+ 0 - 56
route/api_sitemap.py

@@ -1,56 +0,0 @@
-from .tool.func import *
-
-def api_sitemap():
-    with get_db_connect() as conn:
-        curs = conn.cursor()
-
-        if admin_check(None, 'make sitemap') == 1:
-            data = '' + \
-                '<?xml version="1.0" encoding="UTF-8"?>\n' + \
-                '<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">\n' + \
-            ''
-            domain = load_domain('full')
-
-            curs.execute(db_change("select title from data"))
-            all_data = curs.fetchall()
-
-            len_all_data = len(all_data)
-            count = int(len_all_data / 30000)
-            other_count = len_all_data % 30000
-
-            for i in range(count + 1):
-                data += '<sitemap><loc>' + domain + 'sitemap_' + str(i) + '.xml</loc></sitemap>\n'
-
-            data += '' + \
-                '</sitemapindex>' + \
-            ''
-
-            f = open("sitemap.xml", 'w')
-            f.write(data)
-            f.close()
-
-            e = 0
-            for i in range(count + 1):
-                data = '' + \
-                    '<?xml version="1.0" encoding="UTF-8"?>\n' + \
-                    '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">\n' + \
-                ''
-
-                if count == i:
-                    for x in all_data[30000 * i:]:
-                        data += '<url><loc>' + domain + 'w/' + url_pas(x[0]) + '</loc></url>\n'
-                else:
-                    for x in all_data[30000 * i:30000 * (i + 1)]:
-                        data += '<url><loc>' + domain + 'w/' + url_pas(x[0]) + '</loc></url>\n'
-
-                data += '' + \
-                    '</urlset>' + \
-                ''
-
-                f = open("sitemap_" + str(i) + ".xml", 'w')
-                f.write(data)
-                f.close()
-
-            return redirect('/sitemap.xml')
-        else:
-            return re_error('/ban')

+ 76 - 0
route/api_topic.py

@@ -0,0 +1,76 @@
+from .tool.func import *
+
+def api_topic(topic_num = 1, tool = 'normal', num = ''):
+    with get_db_connect() as conn:
+        curs = conn.cursor()
+
+        topic_num = str(topic_num)
+
+        if acl_check('', 'topic_view', topic_num) != 1:
+            if tool == 'normal':
+                if num != '':
+                    curs.execute(db_change(
+                        "select id, data, date, ip, block, top from topic where code = ? and id + 0 = ? + 0 order by id + 0 asc"
+                    ), [
+                        topic_num,
+                        num
+                    ])
+                else:
+                    curs.execute(db_change(
+                        "select id, data, date, ip, block, top from topic where code = ? order by id + 0 asc"
+                    ), [
+                        topic_num
+                    ])
+            elif tool == 'length':
+                curs.execute(db_change("select id from topic where code = ? order by id + 0 desc limit 1"), [topic_num])
+                db_data = curs.fetchall()
+
+                if db_data:
+                    return flask.jsonify({ 'length' : db_data[0][0] })
+                else:
+                    return flask.jsonify({})
+            else:
+                curs.execute(db_change(
+                    "select id, data, date, ip, block, top from topic where code = ? and top = 'O' order by id + 0 asc"
+                ), [
+                    topic_num
+                ])
+
+            data = curs.fetchall()
+            if data:
+                data_a = {}
+                admin = admin_check(3)
+
+                curs.execute(db_change("select ip from topic where code = ? order by id + 0 asc limit 1"), [topic_num])
+                data_f = curs.fetchall()
+                data_f = data_f[0][0] if data_f else ''
+                data_a['data_main'] = {
+                    "ip_first" : ip_pas(data_f, 1),
+                    "admin" : str(admin)
+                }
+
+                ip_a = ip_pas([i[3] for i in data])
+                ip_a_2 = ip_pas([i[3] for i in data], 1)
+                for i in data:
+                    data_v = i[1] if i[4] != 'O' or admin == 1 else ''
+
+                    data_a[i[0]] = {
+                        "data" : data_v,
+                        "date" : i[2],
+                        "ip" : ip_a_2[i[3]],
+                        "blind" : i[4],
+
+                        "ip_pas" : ip_a[i[3]],
+                        "data_pas" : render_set(
+                            doc_data = data_v, 
+                            data_type = 'api_view',
+                            data_in = 'topic_' + topic_num + '_' + i[0],
+                            doc_acl = 0
+                        )
+                    }
+
+                return flask.jsonify(data_a)
+            else:
+                return flask.jsonify({})
+        else:
+            return flask.jsonify({})

+ 0 - 65
route/api_topic_sub.py

@@ -1,65 +0,0 @@
-from .tool.func import *
-
-def api_topic_sub(topic_num = 1, tool = 'normal', num = ''):
-    with get_db_connect() as conn:
-        curs = conn.cursor()
-
-        topic_num = str(topic_num)
-
-        if tool == 'normal':
-            if num != '':
-                curs.execute(db_change(
-                    "select id, data, date, ip, block, top from topic where code = ? and id + 0 = ? + 0 order by id + 0 asc"
-                ), [
-                    topic_num,
-                    num
-                ])
-            else:
-                curs.execute(db_change(
-                    "select id, data, date, ip, block, top from topic where code = ? order by id + 0 asc"
-                ), [
-                    topic_num
-                ]) 
-        else:
-            curs.execute(db_change(
-                "select id, data, date, ip, block, top from topic where code = ? and top = 'O' order by id + 0 asc"
-            ), [
-                topic_num
-            ])
-            
-        data = curs.fetchall()
-        if data:
-            data_a = {}
-            admin = admin_check(3)
-
-            curs.execute(db_change("select ip from topic where code = ? order by id + 0 asc limit 1"), [topic_num])
-            data_f = curs.fetchall()
-            data_f = data_f[0][0] if data_f else ''
-            data_a['data_main'] = {
-                "ip_first" : ip_pas(data_f, 1),
-                "admin" : str(admin)
-            }
-
-            ip_a = ip_pas([i[3] for i in data])
-            ip_a_2 = ip_pas([i[3] for i in data], 1)
-            for i in data:
-                data_v = i[1] if i[4] != 'O' or admin == 1 else ''
-
-                data_a[i[0]] = {
-                    "data" : data_v,
-                    "date" : i[2],
-                    "ip" : ip_a_2[i[3]],
-                    "blind" : i[4],
-
-                    "ip_pas" : ip_a[i[3]],
-                    "data_pas" : render_set(
-                        doc_data = data_v, 
-                        data_type = 'api_view',
-                        data_in = 'topic_' + topic_num + '_' + i[0],
-                        doc_acl = 0
-                    )
-                }
-
-            return flask.jsonify(data_a)
-        else:
-            return flask.jsonify({})

+ 53 - 75
route/api_user_info.py

@@ -15,6 +15,9 @@ def api_user_info(name = ''):
             for user_name in data_list:
                 data_result[user_name] = {}
                 
+                # name part
+                data_result[user_name]['render'] = ip_pas(user_name)
+                
                 # auth part
                 curs.execute(db_change("select data from user_set where id = ? and name = 'acl'"), [user_name])
                 db_data = curs.fetchall()
@@ -24,18 +27,62 @@ def api_user_info(name = ''):
                         if curs.fetchall():
                             data_result[user_name]['auth'] = db_data[0][0]
                         else:
-                            data_result[user_name]['auth'] = 1
+                            data_result[user_name]['auth'] = '1'
                     else:
-                        data_result[user_name]['auth'] = 1
+                        data_result[user_name]['auth'] = '1'
+                else:
+                    data_result[user_name]['auth'] = '0'
+                    
+                # ban part
+                if ban_check(name) == 0:
+                    data_result[user_name]['ban'] = '0'
                 else:
-                    data_result[user_name]['auth'] = 0
+                    data_result[user_name]['ban'] = {}
+                    regex_ban = 0
+                    
+                    curs.execute(db_change("select login, block, end, why from rb where band = 'regex' and ongoing = '1'"))
+                    for db_data in curs.fetchall():
+                        if re.compile(db_data[1]).search(user_name):
+                            regex_ban = 1
+                            
+                            data_result[user_name]['ban']['type'] = 'regex'
+                            if db_data[0] == 'O':
+                                data_result[user_name]['ban']['login_able'] = '1'
+                            else:
+                                data_result[user_name]['ban']['login_able'] = '0'
+                                
+                            if db_data[2] == '':
+                                data_result[user_name]['ban']['period'] = '0'
+                            else:
+                                data_result[user_name]['ban']['period'] = db_data[2]
+                                
+                            data_result[user_name]['ban']['reason'] = db_data[3]
+                            
+                            break
+                            
+                    if regex_ban == 0:
+                        curs.execute(db_change("select login, block, end, why from rb where block = ? and ongoing = '1'"), [user_name])
+                        db_data = curs.fetchall()
+                        if db_data:
+                            data_result[user_name]['ban']['type'] = 'normal'
+                            if db_data[0][0] == 'O':
+                                data_result[user_name]['ban']['login_able'] = '1'
+                            else:
+                                data_result[user_name]['ban']['login_able'] = '0'
+                                
+                            if db_data[0][2] == '':
+                                data_result[user_name]['ban']['period'] = '0'
+                            else:
+                                data_result[user_name]['ban']['period'] = db_data[0][2]
+                                
+                            data_result[user_name]['ban']['reason'] = db_data[0][3]
                 
                 # user document part
                 curs.execute(db_change("select title from data where title = ?"), ['user:' + user_name])
                 if curs.fetchall():
-                    data_result[user_name]['document'] = 1
+                    data_result[user_name]['document'] = '1'
                 else:
-                    data_result[user_name]['document'] = 0
+                    data_result[user_name]['document'] = '0'
 
                 # user title part
                 curs.execute(db_change('select data from user_set where name = "user_title" and id = ?'), [user_name])
@@ -47,73 +94,4 @@ def api_user_info(name = ''):
                     
             return flask.jsonify(data_result)
         else:
-            if flask.request.args.get('render', None):
-                plus_d = ''
-                plus_t = []
-
-                curs.execute(db_change("update rb set ongoing = '' where end < ? and end != '' and ongoing = '1'"), [get_time()])
-                conn.commit()
-
-                plus_d = '''
-                    <table class="user_info_table">
-                        <tbody>
-                            <tr>
-                                <td>''' + load_lang('user_name') + '''</td>
-                                <td>{}</td>
-                            </tr>
-                            <tr>
-                                <td>''' + load_lang('authority') + '''</td>
-                                <td>{}</td>
-                            </tr>
-                            <tr>
-                                <td>''' + load_lang('state') + '''</td>
-                                <td>{}</td>
-                            </tr>
-                        </tbody>
-                    </table>
-                '''
-
-                curs.execute(db_change("select data from user_set where id = ? and name = 'acl'"), [name])
-                data = curs.fetchall()
-                if data:
-                    if data[0][0] != 'user':
-                        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:
-                    plus_t += [load_lang('normal')]
-
-                if ban_check(name) == 0:
-                    plus_t += [load_lang('normal')]
-                else:
-                    plus_t += [load_lang('blocked') + '<br>']
-                    regex_ban = 0
-
-                    curs.execute(db_change("select login, block, end, why from rb where band = 'regex' and ongoing = '1'"))
-                    for test_r in curs.fetchall():
-                        if re.compile(test_r[1]).search(name):
-                            plus_t[1] += load_lang('type') + ' : ' + load_lang('regex')
-                            plus_t[1] += '<br>' + load_lang('period') + ' : ' + (test_r[2] if test_r[2] != '' else load_lang('limitless'))
-                            plus_t[1] += ('<br>' + load_lang('login_able') if test_r[0] == 'O' else '')
-                            plus_t[1] += ('<br>' + load_lang('why') + ' : ' + test_r[3] if test_r[3] != '' else '')
-                            regex_ban = 1
-
-                    if regex_ban == 0:
-                        curs.execute(db_change("select end, login, band, why from rb where block = ? and ongoing = '1'"), [name])
-                        block_data = curs.fetchall()
-                        if block_data:
-                            plus_t[1] += load_lang('type') + ' : ' + (load_lang('band_blocked') if block_data[0][2] == 'O' else load_lang('normal'))
-                            plus_t[1] += (' (' + load_lang('login_able') + ')' if block_data[0][1] != '' else '')
-                            plus_t[1] += '<br>' + load_lang('period') + ' : ' + (block_data[0][0] if block_data[0][0] != '' else load_lang('limitless'))
-                            plus_t[1] += ('<br>' + load_lang('band_blocked') if block_data[0][2] == 'O' else '')
-                            plus_t[1] += ('<br>' + load_lang('why') + ' : ' + block_data[0][3] if block_data[0][3] != '' else '')
-
-                plus_d = plus_d.format(ip_pas(name), plus_t[0], plus_t[1])
-
-                return flask.jsonify({ "data" : plus_d })
-            else:
-                return flask.jsonify({})
+            return flask.jsonify({})

+ 121 - 60
route/edit.py

@@ -1,11 +1,11 @@
 from .tool.func import *
 
-def edit(name = 'Test', name_load = 0, section = 0):
+def edit(name = 'Test', section = 0, do_type = ''):
     with get_db_connect() as conn:
         curs = conn.cursor()
     
         ip = ip_check()
-        if acl_check(name) == 1:
+        if acl_check(name, 'document_edit') == 1:
             return redirect('/raw_acl/' + url_pas(name))
         
         if do_title_length_check(name) == 1:
@@ -47,8 +47,27 @@ def edit(name = 'Test', name_load = 0, section = 0):
             
             curs.execute(db_change("select data from data where title = ?"), [name])
             old = curs.fetchall()
-            if old:  
+            if old:
                 o_data = old[0][0].replace('\r\n', '\n')
+
+                if section != '':
+                    if flask.request.form.get('doc_section_edit_apply', 'X') != 'X':
+                        if flask.request.form.get('doc_section_data_where', '') != '':
+                            data_match_where = flask.request.form.get('doc_section_data_where', '').split(',')
+                            if len(data_match_where) == 2:
+                                data_match_a = int(number_check(data_match_where[0]))
+                                if data_match_where[1] != 'inf':
+                                    data_match_b = int(number_check(data_match_where[1]))
+                                else:
+                                    data_match_b = 'inf'
+
+                                try:
+                                    if data_match_b != 'inf':
+                                        content = o_data[ : data_match_a] + content + o_data[data_match_b : ]
+                                    else:
+                                        content = o_data[ : data_match_a] + content
+                                except:
+                                    pass
     
                 leng = leng_check(len(o_data), len(content))
                 
@@ -63,7 +82,7 @@ def edit(name = 'Test', name_load = 0, section = 0):
     
             curs.execute(db_change("select user from scan where title = ? and type = ''"), [name])
             for scan_user in curs.fetchall():
-                add_alarm(scan_user[0], ip + ' | <a href="/w/' + url_pas(name) + '">' + name + '</a> | Edit')
+                add_alarm(scan_user[0], ip + ' | <a href="/w/' + url_pas(name) + '">' + html.escape(name) + '</a> | Edit')
                     
             history_plus(
                 name,
@@ -90,8 +109,20 @@ def edit(name = 'Test', name_load = 0, section = 0):
             return redirect('/w/' + url_pas(name) + section)
         else:
             editor_top_text = ''
+
+            doc_section_edit_apply = 'X'
+            data_section = ''
+            data_section_where = ''
+
             if edit_repeat == 'get':
-                load_title = name_load
+                if do_type == 'load':
+                    if flask.session and 'edit_load_document' in flask.session:
+                        load_title = flask.session['edit_load_document']
+                    else:
+                        load_title = 0
+                else:
+                    load_title = 0
+                
                 if load_title == 0 and section == '':
                     load_title = name
                     editor_top_text += '<a href="/manager/15/' + url_pas(name) + '">(' + load_lang('load') + ')</a> '
@@ -99,9 +130,49 @@ def edit(name = 'Test', name_load = 0, section = 0):
                     load_title = name
                     
                 curs.execute(db_change("select data from data where title = ?"), [load_title])
-                sql_d = curs.fetchall()
-                data = sql_d[0][0] if sql_d else ''
+                db_data = curs.fetchall()
+                data = db_data[0][0] if db_data else ''
                 data = data.replace('\r\n', '\n')
+
+                if section != '':
+                    curs.execute(db_change('select data from other where name = "markup"'))
+                    db_data = curs.fetchall()
+                    db_data = db_data[0][0] if db_data else 'namumark'
+                    if db_data == 'namumark':
+                        count = 1
+                        data_section = '\n' + data + '\n'
+                        
+                        while 1:
+                            data_match_re = r'\n((={1,6})(#?) ?([^\n]+))\n'
+                            data_match = re.search(data_match_re, data_section)
+                            if not data_match:
+                                data_section = ''
+
+                                break
+                            elif count > section:
+                                data_section = ''
+
+                                break
+
+                            if section == count:
+                                data_section_sub = data_section
+                                data_section_sub = re.sub(data_match_re, '.' * len(data_match.group(0)), data_section_sub, 1)
+
+                                data_match_plus = re.search(data_match_re, data_section_sub)
+                                if data_match_plus:
+                                    data_section = data[data_match.span()[0] : data_match_plus.span()[0] - 1]
+                                    data_section_where = str(data_match.span()[0]) + ',' + str(data_match_plus.span()[0] - 1)
+                                else:
+                                    data_section = data[data_match.span()[0] : ]
+                                    data_section_where = str(data_match.span()[0]) + ',inf'
+
+                                doc_section_edit_apply = 'O'
+
+                                break
+                            else:
+                                data_section = re.sub(data_match_re, '.' * len(data_match.group(0)), data_section, 1)
+
+                            count += 1
             else:
                 data = flask.request.form.get('content', '')
                 warning_edit = load_lang('exp_edit_conflict') + ' '
@@ -117,19 +188,16 @@ def edit(name = 'Test', name_load = 0, section = 0):
     
                 warning_edit += '<hr class="main_hr">'
                 editor_top_text = warning_edit + editor_top_text
+
+            if data_section == '':
+                data_section = data
     
-            editor_top_text += '' + \
-                '<a href="/edit_filter">(' + load_lang('edit_filter_rule') + ')</a>' + \
-                '<hr class="main_hr">' + \
-            ''
+            editor_top_text += '<a href="/edit_filter">(' + load_lang('edit_filter_rule') + ')</a>'
     
             curs.execute(db_change('select data from other where name = "edit_help"'))
             sql_d = curs.fetchall()
             p_text = html.escape(sql_d[0][0]) if sql_d and sql_d[0][0] != '' else load_lang('default_edit_help')
-    
-            data = re.sub(r'\n+$', '', data)
             
-            # 이 파트 JS로 이동 예정
             monaco_on = flask.request.cookies.get('main_css_monaco', '0')
             if monaco_on == '1':
                 editor_display = 'style="display: none;"'
@@ -139,7 +207,18 @@ def edit(name = 'Test', name_load = 0, section = 0):
                             data-name="vs/editor/editor.main" 
                             href="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.20.0/min/vs/editor/editor.main.min.css">
                     <script src="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.20.0/min/vs/loader.min.js"></script>
+                    <script>
+                        function opennamu_edit_turn_off_monaco() {
+                            do_monaco_to_textarea();
+
+                            document.getElementById('opennamu_js_edit_textarea_view').style.display = 'block';
+                            document.getElementById('opennamu_monaco_editor').style.display = 'none';
+                            document.getElementById('opennamu_monaco_editor').remove();
+                        }
+                    </script>
                 '''
+
+                editor_top_text += ' <a href="javascript:opennamu_edit_turn_off_monaco();">(' + load_lang('turn_off_monaco') + ')</a>'
                 
                 if flask.request.cookies.get('main_css_darkmode', '0') == '1':
                     monaco_thema = 'vs-dark'
@@ -149,8 +228,8 @@ def edit(name = 'Test', name_load = 0, section = 0):
                 add_script = '''
                     require.config({ paths: { 'vs': 'https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.20.0/min/vs' }});
                     require(["vs/editor/editor.main"], function () {
-                        window.editor = monaco.editor.create(document.getElementById('monaco_editor'), {
-                            value: document.getElementById('textarea_edit_view').value,
+                        window.editor = monaco.editor.create(document.getElementById('opennamu_monaco_editor'), {
+                            value: document.getElementById('opennamu_js_edit_textarea_view').value,
                             language: 'plaintext',
                             wordWrap: true,
                             theme: \'''' + monaco_thema + '''\',
@@ -163,64 +242,46 @@ def edit(name = 'Test', name_load = 0, section = 0):
                 monaco_display = 'style="display: none;"'
                 add_get_file = ''
                 add_script = ''
-                
-            curs.execute(db_change("select data from other where name = 'markup'"))
-            markup = curs.fetchall()[0][0]
-            
-            server_set = {
-                'section' : section,
-                'markup' : markup
-             }
+
+            if editor_top_text != '':
+                editor_top_text += '<hr class="main_hr">'
+
+            sub_menu = ' (' + str(section) + ')' if section != '' else ''
     
             return easy_minify(flask.render_template(skin_check(), 
-                imp = [name, wiki_set(), wiki_custom(), wiki_css(['(' + load_lang('edit') + ')', 0])],
+                imp = [name, wiki_set(), wiki_custom(), wiki_css(['(' + load_lang('edit') + ')' + sub_menu, 0])],
                 data =  editor_top_text + add_get_file + '''
-                    <span   id="server_set"
-                            style="display: none;">''' + json.dumps(server_set) + '''</span>
                     <form method="post">
+                        <textarea style="display: none;" id="opennamu_js_edit_origin" name="doc_data_org">''' + html.escape(data_section) + '''</textarea>
+                        <textarea style="display: none;" name="doc_section_data_where">''' + data_section_where + '''</textarea>
+                        <input style="display: none;" name="doc_section_edit_apply" value="''' + doc_section_edit_apply + '''">
+
+                        <textarea style="display: none;" id="opennamu_js_edit_textarea" name="content"></textarea>
+                        <input style="display: none;" name="ver" value="''' + doc_ver + '''">
+                        
                         <div>''' + edit_button(monaco_on) + '''</div>
-                        <div    id="monaco_editor"
-                                class="content" 
-                                ''' + monaco_display + '''></div>
-                        <textarea   id="textarea_edit_view"
-                                    ''' + editor_display + '''
-                                    class="content"
-                                    placeholder="''' + p_text + '''">''' + html.escape(data) + '''</textarea>
+                        
+                        <div id="opennamu_monaco_editor" class="content" ''' + monaco_display + '''></div>
+                        <textarea id="opennamu_js_edit_textarea_view" ''' + editor_display + ''' class="content" placeholder="''' + p_text + '''">''' + html.escape(data_section) + '''</textarea>
                         <hr class="main_hr">
-                        <input  placeholder="''' + load_lang('why') + '''" 
-                                name="send">
-                        <textarea   style="display: none;" 
-                                    id="origin">''' + html.escape(data) + '''</textarea>
-                        <textarea   style="display: none;"
-                                    name="content"
-                                    id="content"></textarea>
-                        <input  style="display: none;" 
-                                name="ver" 
-                                value="''' + doc_ver + '''">
+                        
+                        <input placeholder="''' + load_lang('why') + '''" name="send">
                         <hr class="main_hr">
+                        
                         ''' + captcha_get() + ip_warning() + get_edit_text_bottom_check_box() + get_edit_text_bottom() + '''
-                        <button id="save"
-                                type="submit" 
-                                onclick="
-                                    monaco_to_content(); 
-                                    save_stop_exit();
-                                    section_edit_do();
-                                ">''' + load_lang('save') + '''</button>
-                        <button id="preview" 
-                                type="button" 
-                                onclick="
-                                    monaco_to_content();
-                                    load_preview(\'''' + url_pas(name) + '''\');
-                                ">''' + load_lang('preview') + '''</button>
+                        
+                        <button id="opennamu_js_save" type="submit">''' + load_lang('save') + '''</button>
+                        <button id="opennamu_js_preview" type="button">''' + load_lang('preview') + '''</button>
                     </form>
+                    
                     <hr class="main_hr">
-                    <div id="see_preview"></div>
+                    <div id="opennamu_js_preview_area"></div>
+                    
                     <script>
-                        section_edit_init();
                         do_paste_image();
-                        do_not_out();
                         ''' + add_script + '''
                     </script>
+                    <!-- JS : edit.js -->
                 ''',
                 menu = [
                     ['w/' + url_pas(name), load_lang('return')],

+ 2 - 2
route/edit_delete.py

@@ -5,7 +5,7 @@ def edit_delete(name):
         curs = conn.cursor()
 
         ip = ip_check()
-        if acl_check(name) == 1:
+        if acl_check(name, 'document_delete') == 1:
             return re_error('/ban')
 
         curs.execute(db_change("select title from data where title = ?"), [name])
@@ -64,7 +64,7 @@ def edit_delete(name):
                 imp = [name, wiki_set(), wiki_custom(), wiki_css(['(' + load_lang('delete') + ')', 0])],
                 data = '''
                     <form method="post">
-                        <input placeholder="''' + load_lang('why') + '''" name="send" type="text">
+                        <input placeholder="''' + load_lang('why') + '''" name="send">
                         <hr class="main_hr">
                         ''' + captcha_get() + ip_warning() + get_edit_text_bottom_check_box() + get_edit_text_bottom() + '''
                         <button type="submit">''' + load_lang('delete') + '''</button>

+ 1 - 1
route/edit_delete_mutiple.py → route/edit_delete_multiple.py

@@ -1,7 +1,7 @@
 from .tool.func import *
 from . import edit_delete
 
-def edit_delete_mutiple():
+def edit_delete_multiple():
     with get_db_connect() as conn:
         curs = conn.cursor()
 

+ 81 - 30
route/edit_move.py

@@ -4,7 +4,7 @@ def edit_move(name):
     with get_db_connect() as conn:
         curs = conn.cursor()
 
-        if acl_check(name) == 1:
+        if acl_check(name, 'document_move') == 1:
             return re_error('/ban')
         
         if do_title_length_check(name) == 1:
@@ -27,6 +27,8 @@ def edit_move(name):
             agree = flask.request.form.get('copyright_agreement', '')
             time = get_time()
             ip = ip_check()
+            move_option = flask.request.form.get('move_option', 'none')
+            has_error = 0
             
             if do_edit_send_check(send) == 1:
                 return re_error('/error/37')
@@ -34,9 +36,13 @@ def edit_move(name):
             if do_edit_text_bottom_check_box_check(agree) == 1:
                 return re_error('/error/29')
 
+            # 문서 이동 파트 S
             curs.execute(db_change("select title from history where title = ?"), [move_title])
             if curs.fetchall():
-                if flask.request.form.get('move_option', 'normal') == 'merge' and admin_check(None, 'merge documents') == 1:
+                if (
+                    move_option == 'merge' and 
+                    admin_check(None, 'merge documents (' + name + ') (' + move_title + ')') == 1
+                ):
                     curs.execute(db_change("select data from data where title = ?"), [move_title])
                     data = curs.fetchall()
                     if data:
@@ -87,30 +93,26 @@ def edit_move(name):
                             name, 
                             move[0]
                         ])
-
-                    conn.commit()
-
-                    return redirect('/w/' + url_pas(move_title))
-                elif flask.request.form.get('move_option', 'normal') == 'reverse':
-                    var_name = ''
+                elif move_option == 'reverse':
                     i = 0
-                    while 1:
+                    var_name = ''
+                    while var_name == '':
                         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])
-                            curs.execute(db_change("update rc set title = ? where title = ?"), ['test ' + str(i), name])
-
-                            break
+                            var_name = 'test ' + str(i)
                         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 = ?"), [name])
+                    data = curs.fetchall()
+                    if data:
+                        curs.execute(db_change("update data set title = ? where title = ?"), [var_name, name])
+                        curs.execute(db_change("update back set link = ? where link = ?"), [var_name, name])
+
+                    curs.execute(db_change("update history set title = ? where title = ?"), [var_name, name])
+                    curs.execute(db_change("update rc set title = ? where title = ?"), [var_name, name])
+
+                    for title_name in [[move_title, name], [var_name, move_title]]:
                         curs.execute(db_change("select data from data where title = ?"), [title_name[0]])
                         data = curs.fetchall()
                         if data:
@@ -128,18 +130,15 @@ def edit_move(name):
                             ip,
                             send,
                             '0',
-                            t_check = '<a>' + (title_name[0] if title_name[0] != 'test ' + str(i) else name) + '</a> - <a>' + title_name[1] + '</a> move',
+                            t_check = '<a>' + (title_name[0] if title_name[0] != var_name else name) + '</a> - <a>' + title_name[1] + '</a> move',
                             mode = 'move'
                         )
 
                         curs.execute(db_change("update history set title = ? where title = ?"), [title_name[1], title_name[0]])
                         curs.execute(db_change("update rc 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:
+                elif move_option != 'none':
+                    has_error = 1
+            elif move_option != 'none':                
                 curs.execute(db_change("select data from data where title = ?"), [name])
                 data = curs.fetchall()
                 if data:
@@ -166,26 +165,78 @@ def edit_move(name):
 
                 curs.execute(db_change("update history set title = ? where title = ?"), [move_title, name])
                 curs.execute(db_change("update rc set title = ? where title = ?"), [move_title, name])
-                conn.commit()
+                
+            # 문서 이동 파트 E
+            
+            # 토론 이동 파트 S
+            
+            move_option_topic = flask.request.form.get('move_topic_option', 'none')
+            if (
+                move_option_topic == 'merge' and
+                admin_check(None, 'merge document\'s topics (' + name + ') (' + move_title + ')') == 1
+            ):
+                curs.execute(db_change("update rd set title = ? where title = ?"), [move_title, name])
+            elif move_option_topic == 'reverse':
+                i = 0
+                var_name = ''
+                while var_name == '':
+                    curs.execute(db_change("select title from rd where title = ?"), ['test ' + str(i)])
+                    if not curs.fetchall():
+                        var_name = 'test ' + str(i)
+                    else:
+                        i += 1
+                
+                curs.execute(db_change("update rd set title = ? where title = ?"), [var_name, move_title])
+                curs.execute(db_change("update rd set title = ? where title = ?"), [move_title, name])
+                curs.execute(db_change("update rd set title = ? where title = ?"), [name, var_name])
+            elif move_option_topic == 'normal':
+                curs.execute(db_change("select title from rd where title = ?"), [move_title])
+                if curs.fetchall():
+                    has_error = 1
+                else:
+                    curs.execute(db_change("update rd set title = ? where title = ?"), [move_title, name])
+
+            # 토론 이동 파트 E
+                
+            conn.commit()
 
+            if has_error == 0:
                 return redirect('/w/' + url_pas(move_title))
+            else:
+                return re_error('/error/19')
         else:
             return easy_minify(flask.render_template(skin_check(),
                 imp = [name, wiki_set(), wiki_custom(), wiki_css(['(' + load_lang('move') + ')', 0])],
                 data = '''
                     <form method="post">
-                        ''' + ip_warning() + '''
-                        <input placeholder="''' + load_lang('document_name') + '" value="' + name + '''" name="title" type="text">
+                        <span>''' + load_lang('document_name') + '''</span>
                         <hr class="main_hr">
+                        <input value="''' + name + '''" name="title" type="text">
+                        <hr class="main_hr">
+                        
                         <input placeholder="''' + load_lang('why') + '''" name="send" type="text">
                         <hr class="main_hr">
+                        
+                        <h2>''' + load_lang('document') + '''</h2>
                         <select name="move_option">
+                            <option value="none"> ''' + load_lang('dont_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">
+                        
+                        <h2>''' + load_lang('discussion') + '''</h2>
+                        <select name="move_topic_option">
+                            <option value="none"> ''' + load_lang('dont_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() + ip_warning() + get_edit_text_bottom_check_box() + get_edit_text_bottom() + '''
+                        
                         <button type="submit">''' + load_lang('move') + '''</button>
                     </form>
                 ''',

+ 1 - 1
route/edit_revert.py

@@ -8,7 +8,7 @@ def edit_revert(name, num):
         if curs.fetchall() and admin_check(6) != 1:
             return re_error('/error/3')
 
-        if acl_check(name) == 1:
+        if acl_check(name, 'document_edit') == 1:
             return re_error('/ban')
         
         curs.execute(db_change("select data from history where title = ? and id = ?"), [name, str(num)])

+ 14 - 9
route/main_func_upload.py → route/edit_upload.py

@@ -1,11 +1,16 @@
 from .tool.func import *
 
-def main_func_upload():
+def edit_upload():
     with get_db_connect() as conn:
         curs = conn.cursor()
 
         if acl_check(None, 'upload') == 1:
             return re_error('/ban')
+        
+        curs.execute(db_change('select data from other where name = "upload"'))
+        db_data = curs.fetchall()
+        file_max = number_check(db_data[0][0]) if db_data and db_data[0][0] != '' else '2'
+        file_max = int(file_max)
 
         if flask.request.method == 'POST':
             if captcha_post(flask.request.form.get('g-recaptcha-response', flask.request.form.get('g-recaptcha', ''))) == 1:
@@ -14,12 +19,9 @@ def main_func_upload():
                 captcha_post('', 0)
 
             file_data = flask.request.files.getlist("f_data[]", None)
-            if not file_data:
-                return re_error('/error/9')
-
             file_len = len(file_data)
 
-            if (int(wiki_set(3)) * 1000 * 1000 * file_len) < flask.request.content_length:
+            if (file_max * 1000 * 1000 * file_len) < flask.request.content_length:
                 return re_error('/error/17')
 
             if file_len == 1:    
@@ -31,6 +33,9 @@ def main_func_upload():
                 file_num = 1
 
             for data in file_data:
+                if data.filename == '':
+                    return re_error('/error/9')
+                
                 value = os.path.splitext(data.filename)[1]
 
                 curs.execute(db_change("select html from html_filter where kind = 'extension'"))
@@ -108,7 +113,7 @@ def main_func_upload():
                 if file_num:
                     file_num += 1
 
-            conn.commit()
+                conn.commit()
 
             return redirect('/w/file:' + name)
         else:
@@ -126,14 +131,14 @@ def main_func_upload():
             curs.execute(db_change("select data from other where name = 'upload_default'"))
             db_data = curs.fetchall()
             upload_default = html.escape(db_data[0][0]) if db_data and db_data[0][0] != '' else ''
-
+            
             return easy_minify(flask.render_template(skin_check(),
                 imp = [load_lang('upload'), wiki_set(), wiki_custom(), wiki_css([0, 0])],
                 data = '''
                     <a href="/file_filter">(''' + load_lang('file_filter_list') + ''')</a> <a href="/extension_filter">(''' + load_lang('extension_filter_list') + ''')</a>
                     ''' + upload_help + '''
                     <hr class="main_hr">
-                    ''' + load_lang('max_file_size') + ''' : ''' + wiki_set(3) + '''MB
+                    ''' + load_lang('max_file_size') + ''' : ''' + str(file_max) + '''MB
                     <hr class="main_hr">
                     <form method="post" enctype="multipart/form-data" accept-charset="utf8">
                         <input multiple="multiple" type="file" name="f_data[]">
@@ -147,7 +152,7 @@ def main_func_upload():
                         <textarea rows="10" placeholder="''' + load_lang('other') + '''" name="f_lice">''' + upload_default + '''</textarea>
                         <hr class="main_hr">
                         ''' + captcha_get() + '''
-                        <button id="save" type="submit">''' + load_lang('save') + '''</button>
+                        <button id="opennamu_js_save" type="submit">''' + load_lang('save') + '''</button>
                     </form>
                 ''',
                 menu = [['other', load_lang('return')]]

+ 2 - 2
route/filter_inter_wiki_add.py

@@ -150,10 +150,10 @@ def filter_inter_wiki_add(tool, name = None):
                 if stat == '':
                     t_data = [
                         ['86400', load_lang('1_day')],
-                        ['432000', load_lang('5_day')],
+                        ['432000', load_lang('5_day')],
                         ['2592000', load_lang('30_day')],
                         ['15552000', load_lang('180_day')],
-                        ['31104000', load_lang('360_day')],
+                        ['31104000', load_lang('360_day')],
                         ['0', load_lang('limitless')]
                     ]
                     for i in t_data:

+ 122 - 115
route/give_acl.py

@@ -1,132 +1,139 @@
 from .tool.func import *
 
-def give_acl_2(conn, name):
-    curs = conn.cursor()
+def give_acl_2(name):
+    with get_db_connect() as conn:
+        curs = conn.cursor()
 
-    check_ok = ''
-    ip = ip_check()
+        check_ok = ''
+        ip = ip_check()
 
-    if flask.request.method == 'POST':
-        check_data = 'acl (' + name + ')'
-    else:
-        check_data = None
+        if flask.request.method == 'POST':
+            check_data = 'acl (' + name + ')'
+        else:
+            check_data = None
 
-    user_data = re.search(r'^user:(.+)$', name)
-    if user_data:
-        if check_data and ip_or_user(ip) != 0:
-            return redirect('/login')
+        user_data = re.search(r'^user:(.+)$', name)
+        if user_data:
+            if check_data and ip_or_user(ip) != 0:
+                return redirect('/login')
 
-        if user_data.group(1) != ip_check():
+            if user_data.group(1) != ip_check():
+                if admin_check(5) != 1:
+                    if check_data:
+                        return re_error('/error/3')
+                    else:
+                        check_ok = 'disabled'
+        else:
             if admin_check(5) != 1:
                 if check_data:
                     return re_error('/error/3')
                 else:
                     check_ok = 'disabled'
-    else:
-        if admin_check(5) != 1:
-            if check_data:
-                return re_error('/error/3')
+
+        if flask.request.method == 'POST':
+            acl_data = [['decu', flask.request.form.get('decu', '')]]
+            acl_data += [['document_edit_acl', flask.request.form.get('document_edit_acl', '')]]
+            acl_data += [['document_move_acl', flask.request.form.get('document_move_acl', '')]]
+            acl_data += [['document_delete_acl', flask.request.form.get('document_delete_acl', '')]]
+            acl_data += [['dis', flask.request.form.get('dis', '')]]
+            acl_data += [['view', flask.request.form.get('view', '')]]
+            acl_data += [['why', flask.request.form.get('why', '')]]
+
+            curs.execute(db_change("select title from acl where title = ?"), [name])
+            if curs.fetchall():
+                for i in acl_data:
+                    curs.execute(db_change("update acl set data = ? where title = ? and type = ?"), [i[1], name, i[0]])
             else:
-                check_ok = 'disabled'
-
-    if flask.request.method == 'POST':
-        acl_data = [['decu', flask.request.form.get('decu', '')]]
-        acl_data += [['dis', flask.request.form.get('dis', '')]]
-        acl_data += [['view', flask.request.form.get('view', '')]]
-        acl_data += [['why', flask.request.form.get('why', '')]]
-        
-        curs.execute(db_change("select title from acl where title = ?"), [name])
-        if curs.fetchall():
-            for i in acl_data:
-                curs.execute(db_change("update acl set data = ? where title = ? and type = ?"), [i[1], name, i[0]])
+                for i in acl_data:
+                    curs.execute(db_change("insert into acl (title, data, type) values (?, ?, ?)"), [name, i[1], i[0]])
+
+            all_d = ''
+            for i in ['decu', 'document_edit_acl', 'document_move_acl', 'document_delete_acl', 'dis', 'view']:
+                if flask.request.form.get(i, '') == '':
+                    all_d += 'normal'
+                    if i != 'view':
+                        all_d += ' | '
+                else:
+                    all_d += flask.request.form.get(i, '')
+                    if i != 'view':
+                        all_d += ' | '
+
+            admin_check(5, check_data + ' (' + all_d + ')')
+
+            conn.commit()
+
+            return redirect('/acl/' + url_pas(name))
         else:
-            for i in acl_data:
-                curs.execute(db_change("insert into acl (title, data, type) values (?, ?, ?)"), [name, i[1], i[0]])
-
-        all_d = ''
-        for i in ['decu', 'dis', 'view']:
-            if flask.request.form.get(i, '') == '':
-                all_d += 'normal'
-                if i != 'view':
-                    all_d += ' | '
+            data = ''
+            acl_list = get_acl_list('user') if re.search(r'^user:', name) else get_acl_list()
+            if not re.search(r'^user:', name):
+                acl_get_list = [
+                    [load_lang('view_acl'), 'view', '2', '1.'],
+                    [load_lang('document_acl'), 'decu', '3', '1.1.'],
+                    [load_lang('document_edit_acl'), 'document_edit_acl', '4', '1.1.1.'],
+                    [load_lang('document_move_acl'), 'document_move_acl', '4', '1.1.2.'],
+                    [load_lang('document_delete_acl'), 'document_delete_acl', '4', '1.1.3.'],
+                    [load_lang('discussion_acl'), 'dis', '2', '2.'],
+                ]
             else:
-                all_d += flask.request.form.get(i, '')
-                if i != 'view':
-                    all_d += ' | '
-
-        admin_check(5, check_data + ' (' + all_d + ')')
-
-        conn.commit()
-
-        return redirect('/acl/' + url_pas(name))
-    else:
-        data = ''
-        acl_list = get_acl_list('user') if re.search(r'^user:', name) else get_acl_list()
-        if not re.search(r'^user:', name):
-            acl_get_list = [
-                [load_lang('document_acl'), 'decu'], 
-                [load_lang('discussion_acl'), 'dis'], 
-                [load_lang('view_acl'), 'view']
-            ]
-        else:
-            acl_get_list = [
-                [load_lang('document_acl'), 'decu']
-            ]
-            
-        for i in acl_get_list:
+                acl_get_list = [
+                    [load_lang('document_acl'), 'decu', '2', '1.']
+                ]
+
+            for i in acl_get_list:
+                data += '' + \
+                    '<h' + i[2] + '>' + i[3] + ' ' + i[0] + (' (' + load_lang('beta') + ')' if i[2] == '4' else '') + '</h' + i[2] + '>' + \
+                    '<hr class="main_hr">' + \
+                    '<select name="' + i[1] + '" ' + check_ok + '>' + \
+                ''
+
+                curs.execute(db_change("select data from acl where title = ? and type = ?"), [name, i[1]])
+                acl_data = curs.fetchall()
+                for data_list in acl_list:
+                    check = 'selected="selected"' if acl_data and acl_data[0][0] == data_list else ''
+                    data += '<option value="' + data_list + '" ' + check + '>' + (data_list if data_list != '' else 'normal') + '</option>'
+
+                data += '</select>'
+                data += '<hr class="main_hr">'
+
+            curs.execute(db_change("select data from acl where title = ? and type = ?"), [name, 'why'])
+            acl_data = curs.fetchall()
+            acl_why = html.escape(acl_data[0][0]) if acl_data else ''
             data += '' + \
-                '<h2>' + i[0] + '</h2>' + \
                 '<hr class="main_hr">' + \
-                '<select name="' + i[1] + '" ' + check_ok + '>' + \
+                '<input value="' + acl_why + '" placeholder="' + load_lang('why') + '" name="why" ' + check_ok + '>' + \
             ''
-    
-            curs.execute(db_change("select data from acl where title = ? and type = ?"), [name, i[1]])
-            acl_data = curs.fetchall()
-            for data_list in acl_list:
-                check = 'selected="selected"' if acl_data and acl_data[0][0] == data_list else ''
-                data += '<option value="' + data_list + '" ' + check + '>' + (data_list if data_list != '' else 'normal') + '</option>'
-    
-            data += '</select>'
-            data += '<hr class="main_hr">'
-
-        curs.execute(db_change("select data from acl where title = ? and type = ?"), [name, 'why'])
-        acl_data = curs.fetchall()
-        acl_why = html.escape(acl_data[0][0]) if acl_data else ''
-        data += '' + \
-            '<hr class="main_hr">' + \
-            '<input value="' + acl_why + '" placeholder="' + load_lang('why') + '" name="why" type="text" ' + check_ok + '>' + \
-        ''
-
-        data += '''
-            <h2 id="exp">''' + load_lang('explanation') + '''</h2>
-            <ul class="inside_ul">
-                <li>normal : ''' + load_lang('unset') + '''</li>
-                <li>admin : ''' + load_lang('admin_acl') + '''</li>
-                <li>user : ''' + load_lang('member_acl') + '''</li>
-                <li>50_edit : ''' + load_lang('50_edit_acl') + '''</li>
-                <li>all : ''' + load_lang('all_acl') + '''</li>
-                <li>email : ''' + load_lang('email_acl') + '''</li>
-                <li>owner : ''' + load_lang('owner_acl') + '''</li>
-                <li>ban : ''' + load_lang('ban_acl') + '''</li>
-                <li>before : ''' + load_lang('before_acl') + '''</li>
-                <li>30_day : ''' + load_lang('30_day_acl') + '''</li>
-                <li>ban_admin : ''' + load_lang('ban_admin_acl') + '''</li>
-                <li>not_all : ''' + load_lang('not_all_acl') + '''</li>
-            </ul>
-        '''
-
-        return easy_minify(flask.render_template(skin_check(),
-            imp = [name, wiki_set(), wiki_custom(), wiki_css(['(' + load_lang('acl') + ')', 0])],
-            data = '''
-                <form method="post">
-                    <a href="/setting/8">(''' + load_lang('main_acl_setting') + ''')</a>
-                    ''' + data + '''
-                    <button type="submit" ''' + check_ok + '''>''' + load_lang('save') + '''</button>
-                </form>
-            ''',
-            menu = [
-                ['w/' + url_pas(name), load_lang('document')], 
-                ['manager', load_lang('admin')], 
-                ['admin_log?search=' + url_pas('acl (' + name + ')'), load_lang('acl_record')]
-            ]
-        ))
+
+            data += '''
+                <h2 id="exp">''' + load_lang('explanation') + '''</h2>
+                <ul class="inside_ul">
+                    <li>normal : ''' + load_lang('unset') + '''</li>
+                    <li>admin : ''' + load_lang('admin_acl') + '''</li>
+                    <li>user : ''' + load_lang('member_acl') + '''</li>
+                    <li>50_edit : ''' + load_lang('50_edit_acl') + '''</li>
+                    <li>all : ''' + load_lang('all_acl') + '''</li>
+                    <li>email : ''' + load_lang('email_acl') + '''</li>
+                    <li>owner : ''' + load_lang('owner_acl') + '''</li>
+                    <li>ban : ''' + load_lang('ban_acl') + '''</li>
+                    <li>before : ''' + load_lang('before_acl') + '''</li>
+                    <li>30_day : ''' + load_lang('30_day_acl') + '''</li>
+                    <li>ban_admin : ''' + load_lang('ban_admin_acl') + '''</li>
+                    <li>not_all : ''' + load_lang('not_all_acl') + '''</li>
+                </ul>
+            '''
+
+            return easy_minify(flask.render_template(skin_check(),
+                imp = [name, wiki_set(), wiki_custom(), wiki_css(['(' + load_lang('acl') + ')', 0])],
+                data = '''
+                    <form method="post">
+                        <a href="/setting/acl">(''' + load_lang('main_acl_setting') + ''')</a>
+                        ''' + data + '''
+                        <button type="submit" ''' + check_ok + '''>''' + load_lang('save') + '''</button>
+                    </form>
+                ''',
+                menu = [
+                    ['w/' + url_pas(name), load_lang('document')], 
+                    ['manager', load_lang('admin')], 
+                    ['admin_log?search=' + url_pas('acl (' + name + ')'), load_lang('acl_record')]
+                ]
+            ))

+ 56 - 55
route/give_admin.py

@@ -1,67 +1,68 @@
 from .tool.func import *
 
-def give_admin_2(conn, name):
-    curs = conn.cursor()
+def give_admin_2(name):
+    with get_db_connect() as conn:
+        curs = conn.cursor()
 
-    owner = admin_check()
+        owner = admin_check()
 
-    curs.execute(db_change("select data from user_set where id = ? and name = 'acl'"), [name])
-    user_acl = curs.fetchall()
-    if not user_acl:
-        return re_error('/error/2')
-    else:
-        user_acl = user_acl[0][0]
-    
-    if owner != 1:
-        curs.execute(db_change('select name from alist where name = ? and acl = "owner"'), [user_acl])
-        if curs.fetchall():
-            return re_error('/error/3')
+        curs.execute(db_change("select data from user_set where id = ? and name = 'acl'"), [name])
+        user_acl = curs.fetchall()
+        if not user_acl:
+            return re_error('/error/2')
+        else:
+            user_acl = user_acl[0][0]
 
-        if ip_check() == name:
-            return re_error('/error/3')
+        if owner != 1:
+            curs.execute(db_change('select name from alist where name = ? and acl = "owner"'), [user_acl])
+            if curs.fetchall():
+                return re_error('/error/3')
 
-    if flask.request.method == 'POST':
-        if admin_check(7, 'admin (' + name + ')') != 1:
-            return re_error('/error/3')
+            if ip_check() == name:
+                return re_error('/error/3')
 
-        if flask.request.form.get('select', 'X') == 'X':
-            select_data = 'user'
-        else:
-            select_data = flask.request.form.get('select', 'X')
-        
-        curs.execute(db_change('select name from alist where name = ? and acl = "owner"'), [select_data])
-        if owner != 1 and curs.fetchall():
-            return re_error('/error/3')
-            
-        curs.execute(db_change("update user_set set data = ? where id = ? and name = 'acl'"), [
-            select_data, 
-            name
-        ])
+        if flask.request.method == 'POST':
+            if admin_check(7, 'admin (' + name + ')') != 1:
+                return re_error('/error/3')
 
-        conn.commit()
+            if flask.request.form.get('select', 'X') == 'X':
+                select_data = 'user'
+            else:
+                select_data = flask.request.form.get('select', 'X')
 
-        return redirect('/admin/' + url_pas(name))
-    else:
-        if admin_check(7) != 1:
-            return re_error('/error/3')
+            curs.execute(db_change('select name from alist where name = ? and acl = "owner"'), [select_data])
+            if owner != 1 and curs.fetchall():
+                return re_error('/error/3')
 
-        div = '<option value="X">X</option>'
+            curs.execute(db_change("update user_set set data = ? where id = ? and name = 'acl'"), [
+                select_data, 
+                name
+            ])
 
-        curs.execute(db_change('select distinct name from alist order by name asc'))
-        for data in curs.fetchall():
-            if user_acl == data[0]:
-                div = '<option value="' + data[0] + '">' + data[0] + '</option>' + div
-            else:
-                div += '<option value="' + data[0] + '">' + data[0] + '</option>'
+            conn.commit()
+
+            return redirect('/admin/' + url_pas(name))
+        else:
+            if admin_check(7) != 1:
+                return re_error('/error/3')
+
+            div = '<option value="X">X</option>'
+
+            curs.execute(db_change('select distinct name from alist order by name asc'))
+            for data in curs.fetchall():
+                if user_acl == data[0]:
+                    div = '<option value="' + data[0] + '">' + data[0] + '</option>' + div
+                else:
+                    div += '<option value="' + data[0] + '">' + data[0] + '</option>'
 
-        return easy_minify(flask.render_template(skin_check(),
-            imp = [name, wiki_set(), wiki_custom(), wiki_css(['(' + load_lang('authorize') + ')', 0])],
-            data =  '''
-                    <form method="post">
-                        <select name="select">''' + div + '''</select>
-                        <hr class="main_hr">
-                        <button type="submit">''' + load_lang('save') + '''</button>
-                    </form>
-                    ''',
-            menu = [['manager', load_lang('return')]]
-        ))
+            return easy_minify(flask.render_template(skin_check(),
+                imp = [name, wiki_set(), wiki_custom(), wiki_css(['(' + load_lang('authorize') + ')', 0])],
+                data =  '''
+                        <form method="post">
+                            <select name="select">''' + div + '''</select>
+                            <hr class="main_hr">
+                            <button type="submit">''' + load_lang('save') + '''</button>
+                        </form>
+                        ''',
+                menu = [['manager', load_lang('return')]]
+            ))

+ 58 - 57
route/give_admin_groups.py

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

+ 22 - 21
route/give_delete_admin_group.py

@@ -1,27 +1,28 @@
 from .tool.func import *
 
-def give_delete_admin_group_2(conn, name):
-    curs = conn.cursor()
+def give_delete_admin_group_2(name):
+    with get_db_connect() as conn:
+        curs = conn.cursor()
 
-    if admin_check() != 1:
-        return re_error('/error/3')
-    
-    if flask.request.method == 'POST':
-        admin_check(None, 'alist del ' + name)
+        if admin_check() != 1:
+            return re_error('/error/3')
 
-        curs.execute(db_change("delete from alist where name = ?"), [name])
-        curs.execute(db_change("update user_set set data = 'user' where name = 'acl' and data = ?"), [name])
+        if flask.request.method == 'POST':
+            admin_check(None, 'alist del ' + name)
 
-        conn.commit()
+            curs.execute(db_change("delete from alist where name = ?"), [name])
+            curs.execute(db_change("update user_set set data = 'user' where name = 'acl' and data = ?"), [name])
 
-        return redirect('/admin_group')
-    else:
-        return easy_minify(flask.render_template(skin_check(),
-            imp = [load_lang("delete_admin_group"), wiki_set(), wiki_custom(), wiki_css(['(' + name + ')', 0])],
-            data = '''
-                <form method=post>
-                    <button type=submit>''' + load_lang('start') + '''</button>
-                </form>
-            ''',
-            menu = [['admin_group', load_lang('return')]]
-        ))  
+            conn.commit()
+
+            return redirect('/admin_group')
+        else:
+            return easy_minify(flask.render_template(skin_check(),
+                imp = [load_lang("delete_admin_group"), wiki_set(), wiki_custom(), wiki_css(['(' + name + ')', 0])],
+                data = '''
+                    <form method=post>
+                        <button type=submit>''' + load_lang('start') + '''</button>
+                    </form>
+                ''',
+                menu = [['admin_group', load_lang('return')]]
+            ))

+ 124 - 101
route/give_user_ban.py

@@ -1,116 +1,139 @@
 from .tool.func import *
 
-def give_user_ban_2(conn, name):
-    curs = conn.cursor()
+def give_user_ban(name = None, ban_type = ''):
+    with get_db_connect() as conn:
+        curs = conn.cursor()
 
-    band = flask.request.args.get('type', '')
-    ip = ip_check()
-    if ban_check(ip = ip, tool = 'login') == 1:
-    	if ip_or_user(ip) == 1 or admin_check('all', None, ip) == 0:
-            return re_error('/ban')
-    else:
-    	if admin_check(1, None, ip) !=1:
-    	    return re_error('/error/3')
+        ip = ip_check()
+        
+        if ban_check(ip = ip, tool = 'login') == 1:
+            if ip_or_user(ip) == 1 or admin_check('all', None, ip) == 0:
+                return re_error('/ban')
+        else:
+            if admin_check(1, None, ip) != 1:
+                return re_error('/error/3')
 
-    if flask.request.method == 'POST':
-        end = flask.request.form.get('second', '0')
-        end = end if end else '0'
-        name = name if name else flask.request.form.get('name', 'test')
-        regex_get = flask.request.form.get('regex', None)
-        login = flask.request.form.get('login', '')
-        why = flask.request.form.get('why', '')
+        if flask.request.method == 'POST':
+            end = flask.request.form.get('second', '0')
+            end = end if end else '0'
+            
+            regex_get = flask.request.form.get('regex', None)
+            login = flask.request.form.get('login', '')
+            why = flask.request.form.get('why', '')
 
-        if regex_get or band != '':
-            type_d = 'regex' if regex_get else band
+            if ban_type == 'multiple':
+                all_user = re.findall(r'([^\n]+)\n', flask.request.form.get('name', 'test').replace('\r\n', '\n') + '\n')
+            else:
+                if name:
+                    all_user = [name]
+                else:
+                    all_user = [flask.request.form.get('name', 'test')]
 
-            try:
-                re.compile(name)
-            except:
-                return re_error('/error/23')
-        else:
-            type_d = None
+            for name in all_user:
+                if regex_get or ban_type == 'regex':
+                    type_d = 'regex' if regex_get else ban_type
 
-        if type_d:
-            if admin_check(None, 'ban' + (' ' + type_d if type_d else '') + ' (' + name + ')') != 1:
-                return re_error('/error/3')
-        else:
-            if name == ip:
-                if admin_check('all', 'ban (' + name + ')') != 1:
-                    return re_error('/error/3')
-            else:
-            	if admin_check(1, 'ban (' + name + ')') != 1:
-                    return re_error('/error/3')
+                    try:
+                        re.compile(name)
+                    except:
+                        return re_error('/error/23')
+                else:
+                    type_d = None
 
-        ban_insert(
-            name,
-            end,
-            why,
-            login,
-            ip_check(),
-            type_d
-        )
+                if type_d:
+                    if admin_check(None, 'ban' + (' ' + type_d if type_d else '') + ' (' + name + ')') != 1:
+                        return re_error('/error/3')
+                else:
+                    if name == ip:
+                        if admin_check('all', 'ban (' + name + ')') != 1:
+                            return re_error('/error/3')
+                    else:
+                        if admin_check(1, 'ban (' + name + ')') != 1:
+                            return re_error('/error/3')
 
-        return redirect('/block_log')
-    else:
-        curs.execute(db_change("select end, why from rb where block = ? and ongoing = '1' and band = ?"), [name, band])
-        end = curs.fetchall()
-        if end:
-            main_name = name
-            b_now = load_lang('release')
-            now = '(' + b_now + ')'
-            action = 'action="/ban/' + url_pas(name) + ('?type=' + band if band != '' else '') + '"'
+                ban_insert(
+                    name,
+                    end,
+                    why,
+                    login,
+                    ip_check(),
+                    type_d
+                )
 
-            if end[0][0] == '':
-                data = '<ul class="inside_ul"><li>' + load_lang('limitless') + '</li>'
-            else:
-                data = '<ul class="inside_ul"><li>' + load_lang('period') + ' : ' + end[0][0] + '</li>'
+            return redirect('/block_log')
+        else:
+            curs.execute(db_change("select end, why from rb where block = ? and ongoing = '1' and band = ?"), [name, ban_type])
+            end = curs.fetchall()
+            if end:
+                main_name = name
+                b_now = load_lang('release')
+                now = '(' + b_now + ')'
+                
+                if ban_type == 'regex':
+                    action = 'action="/auth/give/ban_regex/' + url_pas(name) + '"'
+                else:
+                    action = 'action="/auth/give/ban/' + url_pas(name) + '"'
+
+                if end[0][0] == '':
+                    data = '<ul class="inside_ul"><li>' + load_lang('limitless') + '</li>'
+                else:
+                    data = '<ul class="inside_ul"><li>' + load_lang('period') + ' : ' + end[0][0] + '</li>'
 
-            curs.execute(db_change("select block from rb where block = ? and login = 'O' and ongoing = '1'"), [name])
-            if curs.fetchall():
-                data += '<li>' + load_lang('login_able') + '</li>'
+                curs.execute(db_change("select block from rb where block = ? and login = 'O' and ongoing = '1'"), [name])
+                if curs.fetchall():
+                    data += '<li>' + load_lang('login_able') + '</li>'
 
-            if end[0][1] != '':
-                data += '<li>' + load_lang('why') + ' : ' + end[0][1] + '</li></ul><hr class="main_hr">'
+                if end[0][1] != '':
+                    data += '<li>' + load_lang('why') + ' : ' + end[0][1] + '</li></ul><hr class="main_hr">'
+                else:
+                    data += '</ul><hr class="main_hr">'
             else:
-                data += '</ul><hr class="main_hr">'
-        else:
-            main_name = load_lang('ban')
-            n_name = '<input placeholder="' + load_lang('name_or_ip_or_regex') + '" value="' + (name if name else '') + '" name="name" type="text"><hr class="main_hr">'
-            regex = '<input type="checkbox" name="regex" ' + ('checked' if band == 'regex' else '') + '> ' + load_lang('regex') + '<hr class="main_hr">'
-            plus = '<input type="checkbox" name="login"> ' + load_lang('login_able') + '<hr class="main_hr">'
-            now = 0
-            b_now = load_lang('ban')
-            action = 'action="/ban"'
-            
-            time_data = [
-                ['86400', load_lang('1_day')],
-                ['432000', load_lang('5_day')],
-                ['2592000', load_lang('30_day')],
-                ['15552000', load_lang('180_day')],
-                ['31104000', load_lang('360_day')],
-                ['0', load_lang('limitless')]
-            ]
-            insert_data = ''
-            for i in time_data:
-                insert_data += '<a href="javascript:insert_v(\'second\', \'' + i[0] + '\')">(' + i[1] + ')</a> '
+                if ban_type == 'multiple':
+                    main_name = load_lang('multiple_ban')
+                    n_name = '<textarea rows="25" placeholder="' + load_lang('name_or_ip_or_regex_multiple') + '" name="name"></textarea><hr class="main_hr">'
+                else:
+                    main_name = load_lang('ban')
+                    n_name = '<input placeholder="' + load_lang('name_or_ip_or_regex') + '" value="' + (name if name else '') + '" name="name"><hr class="main_hr">'
+                
+                regex = '<input type="checkbox" name="regex" ' + ('checked' if ban_type == 'regex' else '') + '> ' + load_lang('regex') + '<hr class="main_hr">'
+                plus = '<input type="checkbox" name="login"> ' + load_lang('login_able') + '<hr class="main_hr">'
+                now = 0
+                b_now = load_lang('ban')
+                
+                if ban_type == 'multiple':
+                    action = 'action="/auth/give/ban_multiple"'
+                else:
+                    action = 'action="/auth/give/ban"'
+
+                time_data = [
+                    ['86400', load_lang('1_day')],
+                    ['432000', load_lang('5_day')],
+                    ['2592000', load_lang('30_day')],
+                    ['15552000', load_lang('180_day')],
+                    ['31104000', load_lang('360_day')],
+                    ['0', load_lang('limitless')]
+                ]
+                insert_data = ''
+                for i in time_data:
+                    insert_data += '<a href="javascript:insert_v(\'second\', \'' + i[0] + '\')">(' + i[1] + ')</a> '
 
-            data = n_name + '''
-                ''' + regex + '''
-                <script>function insert_v(name, data) { document.getElementById(name).value = data; }</script>''' + insert_data + '''
-                <hr class="main_hr">
-                <input placeholder="''' + load_lang('ban_period') + ''' (''' + load_lang('second') + ''')" name="second" id="second" type="text">
-                <hr class="main_hr">
-                <input placeholder="''' + load_lang('why') + '''" name="why" type="text">
-                <hr class="main_hr">
-            ''' + plus
+                data = n_name + '''
+                    ''' + regex + '''
+                    <script>function insert_v(name, data) { document.getElementById(name).value = data; }</script>''' + insert_data + '''
+                    <hr class="main_hr">
+                    <input placeholder="''' + load_lang('ban_period') + ''' (''' + load_lang('second') + ''')" name="second" id="second" type="text">
+                    <hr class="main_hr">
+                    <input placeholder="''' + load_lang('why') + '''" name="why" type="text">
+                    <hr class="main_hr">
+                ''' + plus
 
-        return easy_minify(flask.render_template(skin_check(),
-            imp = [main_name, wiki_set(), wiki_custom(), wiki_css([now, 0])],
-            data = '''
-                <form method="post" ''' + action + '''>
-                    ''' + data + '''
-                    <button type="submit">''' + b_now + '''</button>
-                </form>
-            ''',
-            menu = [['manager', load_lang('return')]]
-        ))   
+            return easy_minify(flask.render_template(skin_check(),
+                imp = [main_name, wiki_set(), wiki_custom(), wiki_css([now, 0])],
+                data = '''
+                    <form method="post" ''' + action + '''>
+                        ''' + data + '''
+                        <button type="submit">''' + b_now + '''</button>
+                    </form>
+                ''',
+                menu = [['manager', load_lang('return')]]
+            ))   

+ 163 - 162
route/give_user_check.py

@@ -1,178 +1,179 @@
 from .tool.func import *
 
-def give_user_check_2(conn, name):
-    curs = conn.cursor()
-
-    plus_id = flask.request.args.get('plus', None)
-
-    if admin_check('all', None, name) == 1 or (plus_id and admin_check('all', None, plus_id) == 1):
-        if admin_check() != 1:
-            return re_error('/error/4')
-
-    num = int(number_check(flask.request.args.get('num', '1')))
-    sql_num = (num * 50 - 50) if num * 50 > 0 else 0
-    
-    div = ''
-    check_type = flask.request.args.get('type', '')
-
-    if admin_check(4, (check_type + ' ' if check_type != '' else '') + 'check (' + name + ')') != 1:
-        return re_error('/error/3')
-
-    if check_type == '':
-        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 id="main_table_top_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">
-                    '''
+def give_user_check_2(name):
+    with get_db_connect() as conn:
+        curs = conn.cursor()
 
-        if plus_id:
-            plus = "or " + ('ip' if ip_or_user(plus_id) == 1 else 'name') + " = ? "
-            set_list = [name, plus_id, sql_num]
-            
-            if num == 1:
-                curs.execute(db_change("" + \
-                    "select distinct ip from ua_d " + \
-                    "where " + ('ip' if ip_or_user(name) == 1 else 'name') + " = ? or " + ('ip' if ip_or_user(plus_id) == 1 else 'name') + " = ? "
-                ""), [name, plus_id])
-                all_ip_count = len(curs.fetchall())
-                
-                curs.execute(db_change("" + \
-                    "select distinct ip from ua_d " + \
-                    "where " + ('ip' if ip_or_user(name) == 1 else 'name') + " = ?" + \
-                ""), [name])
-                a_ip_count = len(curs.fetchall())
-                
-                curs.execute(db_change("" + \
-                    "select distinct ip from ua_d " + \
-                    "where " + ('ip' if ip_or_user(plus_id) == 1 else 'name') + " = ? "
-                ""), [plus_id])
-                b_ip_count = len(curs.fetchall())
-                
-                if a_ip_count + b_ip_count != all_ip_count:
-                    div += load_lang('same_ip_exist') + '<hr class="main_hr">'    
-        else:
-            plus = ''
-            set_list = [name, sql_num]
-
-        curs.execute(db_change("" + \
-            "select name, ip, ua, today from ua_d " + \
-            "where " + ('ip' if ip_or_user(name) == 1 else 'name') + " = ? " + \
-            plus + \
-            "order by today desc limit ?, 50" + \
-        ""), set_list)
-
-        record = curs.fetchall()
-        if record:
-            if not plus_id:
-                div = '' + \
-                    '<a href="/manager/14?plus=' + url_pas(name) + '">(' + load_lang('compare') + ')</a> ' + \
-                    '<a href="/check/' + url_pas(name) + '?type=simple">(' + load_lang('simple_check') + ')</a>' + \
-                    '<hr class="main_hr">' + \
-                '' + div
+        plus_id = flask.request.args.get('plus', None)
+
+        if admin_check('all', None, name) == 1 or (plus_id and admin_check('all', None, plus_id) == 1):
+            if admin_check() != 1:
+                return re_error('/error/4')
+
+        num = int(number_check(flask.request.args.get('num', '1')))
+        sql_num = (num * 50 - 50) if num * 50 > 0 else 0
+
+        div = ''
+        check_type = flask.request.args.get('type', '')
+
+        if admin_check(4, (check_type + ' ' if check_type != '' else '') + 'check (' + name + ')') != 1:
+            return re_error('/error/3')
+
+        if check_type == '':
+            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 id="main_table_top_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">
+                        '''
+
+            if plus_id:
+                plus = "or " + ('ip' if ip_or_user(plus_id) == 1 else 'name') + " = ? "
+                set_list = [name, plus_id, sql_num]
+
+                if num == 1:
+                    curs.execute(db_change("" + \
+                        "select distinct ip from ua_d " + \
+                        "where " + ('ip' if ip_or_user(name) == 1 else 'name') + " = ? or " + ('ip' if ip_or_user(plus_id) == 1 else 'name') + " = ? "
+                    ""), [name, plus_id])
+                    all_ip_count = len(curs.fetchall())
+
+                    curs.execute(db_change("" + \
+                        "select distinct ip from ua_d " + \
+                        "where " + ('ip' if ip_or_user(name) == 1 else 'name') + " = ?" + \
+                    ""), [name])
+                    a_ip_count = len(curs.fetchall())
+
+                    curs.execute(db_change("" + \
+                        "select distinct ip from ua_d " + \
+                        "where " + ('ip' if ip_or_user(plus_id) == 1 else 'name') + " = ? "
+                    ""), [plus_id])
+                    b_ip_count = len(curs.fetchall())
+
+                    if a_ip_count + b_ip_count != all_ip_count:
+                        div += load_lang('same_ip_exist') + '<hr class="main_hr">'    
             else:
-                div = '' + \
-                    '<a href="/check/' + url_pas(name) + '">(' + name + ')</a> ' + \
-                    '<a href="/check/' + url_pas(plus_id) + '">(' + plus_id + ')</a>' + \
-                    '<hr class="main_hr">' + \
-                '' + div
-
-            div += '''
-                <table id="main_table_set">
-                    <tbody>
-                        <tr id="main_table_top_tr">
-                            <td id="main_table_width">''' + load_lang('name') + '''</td>
-                            <td id="main_table_width">''' + load_lang('ip') + '''</td>
-                            <td id="main_table_width">''' + load_lang('time') + '''</td>
-                        </tr>
-            '''
-
-            set_n = 0
-            for data in record:
-                if data[2]:
-                    if len(data[2]) > 300:
-                        ua = '' + \
-                            '<a href="javascript:void();" onclick="document.getElementById(\'check_' + str(set_n) + '\').style.display=\'block\';">(300+)</a>' + \
-                            '<div id="check_' + str(set_n) + '" style="display:none;">' + html.escape(data[2]) + '</div>' + \
-                        ''
-                        set_n += 1
-                    else:
-                        ua = html.escape(data[2])
+                plus = ''
+                set_list = [name, sql_num]
+
+            curs.execute(db_change("" + \
+                "select name, ip, ua, today from ua_d " + \
+                "where " + ('ip' if ip_or_user(name) == 1 else 'name') + " = ? " + \
+                plus + \
+                "order by today desc limit ?, 50" + \
+            ""), set_list)
+
+            record = curs.fetchall()
+            if record:
+                if not plus_id:
+                    div = '' + \
+                        '<a href="/manager/14?plus=' + url_pas(name) + '">(' + load_lang('compare') + ')</a> ' + \
+                        '<a href="/check/' + url_pas(name) + '?type=simple">(' + load_lang('simple_check') + ')</a>' + \
+                        '<hr class="main_hr">' + \
+                    '' + div
                 else:
-                    ua = '<br>'
+                    div = '' + \
+                        '<a href="/check/' + url_pas(name) + '">(' + name + ')</a> ' + \
+                        '<a href="/check/' + url_pas(plus_id) + '">(' + plus_id + ')</a>' + \
+                        '<hr class="main_hr">' + \
+                    '' + div
 
                 div += '''
-                    <tr>
-                        <td>
-                            <a href="/check/''' + url_pas(data[0]) + '''">''' + data[0] + '''</a>
-                            <a  href="/check_delete''' + \
-                                '''?name=''' + url_pas(data[0]) + \
-                                '''&ip=''' + url_pas(data[1]) + \
-                                '''&time=''' + url_pas(data[3].replace(' ', '').replace(':', '').replace('-', '')) + \
-                                '''&return_type=''' + ('0' if ip_or_user(name) == 0 else '1') + '''">
-                                (''' + load_lang('delete') + ''')
-                            </a>
-                        </td>
-                        <td><a href="/check/''' + url_pas(data[1]) + '''">''' + data[1] + '''</a></td>
-                        <td>''' + data[3] + '''</td>
-                    </tr>
-                    <tr>
-                        <td colspan="3">''' + ua + '''</td>
-                    </tr>
+                    <table id="main_table_set">
+                        <tbody>
+                            <tr id="main_table_top_tr">
+                                <td id="main_table_width">''' + load_lang('name') + '''</td>
+                                <td id="main_table_width">''' + load_lang('ip') + '''</td>
+                                <td id="main_table_width">''' + load_lang('time') + '''</td>
+                            </tr>
                 '''
 
-            div += '''
-                    </tbody>
-                </table>
-            '''
-            
-        div += next_fix(
-            '/check/' + url_pas(name) + ('?plus=' + plus_id + '&num=' if plus_id else '?num='), 
-            num, 
-            record
-        )
-
-        return easy_minify(flask.render_template(skin_check(),
-            imp = [load_lang('check'), wiki_set(), wiki_custom(), wiki_css([0, 0])],
-            data = div,
-            menu = [['manager', load_lang('return')]]
-        ))
-    else:
-        curs.execute(db_change("" + \
-            "select distinct " + ('name' if ip_or_user(name) == 1 else 'ip') + " from ua_d " + \
-            "where " + ('ip' if ip_or_user(name) == 1 else 'name') + " = ? "
-            "order by today desc limit ?, 50" + \
-        ""), [name, sql_num])
-        record = curs.fetchall()
+                set_n = 0
+                for data in record:
+                    if data[2]:
+                        if len(data[2]) > 300:
+                            ua = '' + \
+                                '<a href="javascript:void();" onclick="document.getElementById(\'check_' + str(set_n) + '\').style.display=\'block\';">(300+)</a>' + \
+                                '<div id="check_' + str(set_n) + '" style="display:none;">' + html.escape(data[2]) + '</div>' + \
+                            ''
+                            set_n += 1
+                        else:
+                            ua = html.escape(data[2])
+                    else:
+                        ua = '<br>'
 
-        div = ''
-        for i in record:
-            div += '<li><a href="/check/' + url_pas(i[0]) + '?type=simple">' + i[0] + '</a></li>'
+                    div += '''
+                        <tr>
+                            <td>
+                                <a href="/check/''' + url_pas(data[0]) + '''">''' + data[0] + '''</a>
+                                <a  href="/check_delete''' + \
+                                    '''?name=''' + url_pas(data[0]) + \
+                                    '''&ip=''' + url_pas(data[1]) + \
+                                    '''&time=''' + url_pas(data[3].replace(' ', '').replace(':', '').replace('-', '')) + \
+                                    '''&return_type=''' + ('0' if ip_or_user(name) == 0 else '1') + '''">
+                                    (''' + load_lang('delete') + ''')
+                                </a>
+                            </td>
+                            <td><a href="/check/''' + url_pas(data[1]) + '''">''' + data[1] + '''</a></td>
+                            <td>''' + data[3] + '''</td>
+                        </tr>
+                        <tr>
+                            <td colspan="3">''' + ua + '''</td>
+                        </tr>
+                    '''
+
+                div += '''
+                        </tbody>
+                    </table>
+                '''
 
-        if div != '':
-            div = '<ul class="inside_ul">' + div + '</ul>'
             div += next_fix(
-                '/check/' + url_pas(name) + '?type=' + check_type + '&num=', 
+                '/check/' + url_pas(name) + ('?plus=' + plus_id + '&num=' if plus_id else '?num='), 
                 num, 
                 record
             )
 
-        return easy_minify(flask.render_template(skin_check(),
-            imp = [name, wiki_set(), wiki_custom(), wiki_css(['(' + load_lang('simple_check') + ')', 0])],
-            data = div,
-            menu = [['check/' + url_pas(name), load_lang('return')]]
-        ))
+            return easy_minify(flask.render_template(skin_check(),
+                imp = [load_lang('check'), wiki_set(), wiki_custom(), wiki_css([0, 0])],
+                data = div,
+                menu = [['manager', load_lang('return')]]
+            ))
+        else:
+            curs.execute(db_change("" + \
+                "select distinct " + ('name' if ip_or_user(name) == 1 else 'ip') + " from ua_d " + \
+                "where " + ('ip' if ip_or_user(name) == 1 else 'name') + " = ? "
+                "order by today desc limit ?, 50" + \
+            ""), [name, sql_num])
+            record = curs.fetchall()
+
+            div = ''
+            for i in record:
+                div += '<li><a href="/check/' + url_pas(i[0]) + '?type=simple">' + i[0] + '</a></li>'
+
+            if div != '':
+                div = '<ul class="inside_ul">' + div + '</ul>'
+                div += next_fix(
+                    '/check/' + url_pas(name) + '?type=' + check_type + '&num=', 
+                    num, 
+                    record
+                )
+
+            return easy_minify(flask.render_template(skin_check(),
+                imp = [name, wiki_set(), wiki_custom(), wiki_css(['(' + load_lang('simple_check') + ')', 0])],
+                data = div,
+                menu = [['check/' + url_pas(name), load_lang('return')]]
+            ))

+ 44 - 43
route/give_user_check_delete.py

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

+ 31 - 30
route/list_acl.py

@@ -1,38 +1,39 @@
 from .tool.func import *
 
-def list_acl_2(conn):
-    curs = conn.cursor()
+def list_acl_2():
+    with get_db_connect() as conn:
+        curs = conn.cursor()
 
-    num = int(number_check(flask.request.args.get('num', '1')))
-    sql_num = (num * 50 - 50) if num * 50 > 0 else 0
-    div = '<ul class="inside_ul">'
+        num = int(number_check(flask.request.args.get('num', '1')))
+        sql_num = (num * 50 - 50) if num * 50 > 0 else 0
+        div = '<ul class="inside_ul">'
 
-    curs.execute(db_change(
-        "select distinct title, data, type from acl where data != '' and not title like 'user:%' order by title desc limit ?, 50"
-    ), [sql_num])
-    list_data = curs.fetchall()
-    for data in list_data:
-        curs.execute(db_change("select time from re_admin where what like ? order by time desc limit 1"), ['acl (' + data[0] + ')%'])
-        time_data = curs.fetchall()
-        time_data = (time_data[0][0] + ' | ') if time_data else ''
+        curs.execute(db_change(
+            "select distinct title, data, type from acl where data != '' and not title like 'user:%' order by title desc limit ?, 50"
+        ), [sql_num])
+        list_data = curs.fetchall()
+        for data in list_data:
+            curs.execute(db_change("select time from re_admin where what like ? order by time desc limit 1"), ['acl (' + data[0] + ')%'])
+            time_data = curs.fetchall()
+            time_data = (time_data[0][0] + ' | ') if time_data else ''
 
-        curs.execute(db_change("select data from acl where title = ? and type = 'why'"), [data[0]])
-        why_data = curs.fetchall()
-        why_data = (' | ' + why_data[0][0]) if why_data and why_data[0][0] != '' else ''
+            curs.execute(db_change("select data from acl where title = ? and type = 'why'"), [data[0]])
+            why_data = curs.fetchall()
+            why_data = (' | ' + why_data[0][0]) if why_data and why_data[0][0] != '' else ''
 
-        div += '' + \
-            '<li>' + \
-                time_data + \
-                '<a href="/acl/' + url_pas(data[0]) + '">' + html.escape(data[0]) + '</a>' + \
-                why_data + \
-            '</li>' + \
-        ''
+            div += '' + \
+                '<li>' + \
+                    time_data + \
+                    '<a href="/acl/' + url_pas(data[0]) + '">' + html.escape(data[0]) + '</a>' + \
+                    why_data + \
+                '</li>' + \
+            ''
 
-    div += '</ul>'
-    div += next_fix('/acl_list?num=', num, list_data)
+        div += '</ul>'
+        div += next_fix('/acl_list?num=', num, list_data)
 
-    return easy_minify(flask.render_template(skin_check(),
-        imp = [load_lang('acl_document_list'), wiki_set(), wiki_custom(), wiki_css([0, 0])],
-        data = div,
-        menu = [['other', load_lang('return')]]
-    ))
+        return easy_minify(flask.render_template(skin_check(),
+            imp = [load_lang('acl_document_list'), wiki_set(), wiki_custom(), wiki_css([0, 0])],
+            data = div,
+            menu = [['other', load_lang('return')]]
+        ))

+ 19 - 18
route/list_admin.py

@@ -1,25 +1,26 @@
 from .tool.func import *
 
-def list_admin_2(conn):
-    curs = conn.cursor()
+def list_admin_2():
+    with get_db_connect() as conn:
+        curs = conn.cursor()
 
-    div = '<ul class="inside_ul">'
+        div = '<ul class="inside_ul">'
 
-    curs.execute(db_change(
-        "select id, data from user_set where name = 'acl' and not data = 'user'"
-    ))
-    for data in curs.fetchall():
-        name = '' + \
-            ip_pas(data[0]) + ' ' + \
-            '<a href="/admin_plus/' + url_pas(data[1]) + '">(' + data[1] + ')</a>' + \
-        ''
+        curs.execute(db_change(
+            "select id, data from user_set where name = 'acl' and not data = 'user'"
+        ))
+        for data in curs.fetchall():
+            name = '' + \
+                ip_pas(data[0]) + ' ' + \
+                '<a href="/admin_plus/' + url_pas(data[1]) + '">(' + data[1] + ')</a>' + \
+            ''
 
-        div += '<li>' + name + '</li>'
+            div += '<li>' + name + '</li>'
 
-    div += '</ul>'
+        div += '</ul>'
 
-    return easy_minify(flask.render_template(skin_check(),
-        imp = [load_lang('admin_list'), wiki_set(), wiki_custom(), wiki_css([0, 0])],
-        data = div,
-        menu = [['other', load_lang('return')]]
-    ))
+        return easy_minify(flask.render_template(skin_check(),
+            imp = [load_lang('admin_list'), wiki_set(), wiki_custom(), wiki_css([0, 0])],
+            data = div,
+            menu = [['other', load_lang('return')]]
+        ))

+ 27 - 26
route/list_admin_group.py

@@ -1,34 +1,35 @@
 from .tool.func import *
 
-def list_admin_group_2(conn):
-    curs = conn.cursor()
+def list_admin_group_2():
+    with get_db_connect() as conn:
+        curs = conn.cursor()
 
-    list_data = '<ul class="inside_ul">'
-    org_acl_list = get_default_admin_group()
+        list_data = '<ul class="inside_ul">'
+        org_acl_list = get_default_admin_group()
 
-    curs.execute(db_change("select distinct name from alist order by name asc"))
-    for data in curs.fetchall():            
-        if  admin_check() == 1 and \
-            not data[0] in org_acl_list:
-            delete_admin_group = ' <a href="/delete_admin_group/' + url_pas(data[0]) + '">(' + load_lang("delete") + ')</a>'
-        else:
-            delete_admin_group = ''
+        curs.execute(db_change("select distinct name from alist order by name asc"))
+        for data in curs.fetchall():            
+            if  admin_check() == 1 and \
+                not data[0] in org_acl_list:
+                delete_admin_group = ' <a href="/delete_admin_group/' + url_pas(data[0]) + '">(' + load_lang("delete") + ')</a>'
+            else:
+                delete_admin_group = ''
+
+            list_data += '' + \
+                '<li>' + \
+                    '<a href="/admin_plus/' + url_pas(data[0]) + '">' + html.escape(data[0]) + '</a>' + \
+                    delete_admin_group + \
+                '</li>' + \
+            ''
 
         list_data += '' + \
-            '<li>' + \
-                '<a href="/admin_plus/' + url_pas(data[0]) + '">' + html.escape(data[0]) + '</a>' + \
-                delete_admin_group + \
-            '</li>' + \
+            '</ul>' + \
+            '<hr class="main_hr">' + \
+            '<a href="/manager/8">(' + load_lang('add') + ')</a>' + \
         ''
 
-    list_data += '' + \
-        '</ul>' + \
-        '<hr class="main_hr">' + \
-        '<a href="/manager/8">(' + load_lang('add') + ')</a>' + \
-    ''
-
-    return easy_minify(flask.render_template(skin_check(),
-        imp = [load_lang('admin_group_list'), wiki_set(), wiki_custom(), wiki_css([0, 0])],
-        data = list_data,
-        menu = [['manager', load_lang('return')]]
-    ))    
+        return easy_minify(flask.render_template(skin_check(),
+            imp = [load_lang('admin_group_list'), wiki_set(), wiki_custom(), wiki_css([0, 0])],
+            data = list_data,
+            menu = [['manager', load_lang('return')]]
+        ))

+ 31 - 30
route/list_admin_use.py

@@ -1,38 +1,39 @@
 from .tool.func import *
 
-def list_admin_use_2(conn):
-    curs = conn.cursor()
+def list_admin_use_2():
+    with get_db_connect() as conn:
+        curs = conn.cursor()
 
-    num = int(number_check(flask.request.args.get('num', '1')))
-    sql_num = (num * 50 - 50) if num * 50 > 0 else 0
+        num = int(number_check(flask.request.args.get('num', '1')))
+        sql_num = (num * 50 - 50) if num * 50 > 0 else 0
 
-    if flask.request.method == 'POST':
-        return redirect('/admin_log?search=' + flask.request.form.get('search', 'normal'))
-    else:
-        list_data = '<ul class="inside_ul">'
-
-        if flask.request.args.get('search', 'normal') == 'normal':
-            curs.execute(db_change("select who, what, time from re_admin order by time desc limit ?, 50"), [sql_num])
+        if flask.request.method == 'POST':
+            return redirect('/admin_log?search=' + flask.request.form.get('search', 'normal'))
         else:
-            curs.execute(db_change("select who, what, time from re_admin where what like ? order by time desc limit ?, 50"), [
-                flask.request.args.get('search', 'normal') + "%",
-                sql_num
-            ])
+            list_data = '<ul class="inside_ul">'
+
+            if flask.request.args.get('search', 'normal') == 'normal':
+                curs.execute(db_change("select who, what, time from re_admin order by time desc limit ?, 50"), [sql_num])
+            else:
+                curs.execute(db_change("select who, what, time from re_admin where what like ? order by time desc limit ?, 50"), [
+                    flask.request.args.get('search', 'normal') + "%",
+                    sql_num
+                ])
 
-        get_list = curs.fetchall()
-        for data in get_list:
-            list_data += '<li>' + ip_pas(data[0]) + ' / ' + html.escape(data[1]) + ' / ' + data[2] + '</li>'
+            get_list = curs.fetchall()
+            for data in get_list:
+                list_data += '<li>' + ip_pas(data[0]) + ' / ' + html.escape(data[1]) + ' / ' + data[2] + '</li>'
 
-        list_data += '</ul>'
-        list_data += next_fix('/admin_log?num=', num, get_list)
+            list_data += '</ul>'
+            list_data += next_fix('/admin_log?num=', num, get_list)
 
-        return easy_minify(flask.render_template(skin_check(),
-            imp = [load_lang('authority_use_list'), wiki_set(), wiki_custom(), wiki_css([0, 0])],
-            data = '''
-                <form method="post">
-                    <input name="search" id="admin_log_search"> <button type="submit">''' + load_lang('search') + '''</button>
-                </form>
-                <hr class=\"main_hr\">
-            ''' + list_data,
-            menu = [['other', load_lang('return')]]
-        ))
+            return easy_minify(flask.render_template(skin_check(),
+                imp = [load_lang('authority_use_list'), wiki_set(), wiki_custom(), wiki_css([0, 0])],
+                data = '''
+                    <form method="post">
+                        <input name="search" id="admin_log_search"> <button type="submit">''' + load_lang('search') + '''</button>
+                    </form>
+                    <hr class=\"main_hr\">
+                ''' + list_data,
+                menu = [['other', load_lang('return')]]
+            ))

+ 17 - 19
route/list_image_file.py

@@ -1,26 +1,24 @@
 from .tool.func import *
 
-def list_image_file_2(conn):
-    curs = conn.cursor()
+def list_image_file_2():
+    with get_db_connect() as conn:
+        curs = conn.cursor()
 
-    num = int(number_check(flask.request.args.get('num', '1')))
-    if num * 50 > 0:
-        sql_num = num * 50 - 50
-    else:
-        sql_num = 0
+        num = int(number_check(flask.request.args.get('num', '1')))
+        sql_num = (num * 50 - 50) if num * 50 > 0 else 0
 
-    list_data = '<ul class="inside_ul">'
-    back = ''
+        list_data = '<ul class="inside_ul">'
+        back = ''
 
-    curs.execute(db_change("select title from data where title like 'file:%' limit ?, 50"), [sql_num])
-    data_list = curs.fetchall()
-    for data in data_list:
-        list_data += '<li><a href="/w/' + url_pas(data[0]) + '">' + html.escape(data[0]) + '</a></li>'
+        curs.execute(db_change("select title from data where title like 'file:%' limit ?, 50"), [sql_num])
+        data_list = curs.fetchall()
+        for data in data_list:
+            list_data += '<li><a href="/w/' + url_pas(data[0]) + '">' + html.escape(data[0]) + '</a></li>'
 
-    list_data += next_fix('/image_file_list?num=', num, data_list)
+        list_data += next_fix('/image_file_list?num=', num, data_list)
 
-    return easy_minify(flask.render_template(skin_check(),
-        imp = [load_lang('image_file_list'), wiki_set(), wiki_custom(), wiki_css([0, 0])],
-        data = list_data,
-        menu = [['other', load_lang('return')]]
-    ))    
+        return easy_minify(flask.render_template(skin_check(),
+            imp = [load_lang('image_file_list'), wiki_set(), wiki_custom(), wiki_css([0, 0])],
+            data = list_data,
+            menu = [['other', load_lang('return')]]
+        ))

+ 18 - 17
route/list_long_page.py

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

+ 24 - 23
route/list_please.py

@@ -1,31 +1,32 @@
 from .tool.func import *
 
-def list_please_2(conn):
-    curs = conn.cursor()
+def list_please_2():
+    with get_db_connect() as conn:
+        curs = conn.cursor()
 
-    num = int(number_check(flask.request.args.get('num', '1')))
-    sql_num = (num * 50 - 50) if num * 50 > 0 else 0
+        num = int(number_check(flask.request.args.get('num', '1')))
+        sql_num = (num * 50 - 50) if num * 50 > 0 else 0
 
-    curs.execute(db_change('select data from other where name = "count_all_title"'))
-    if int(curs.fetchall()[0][0]) > 30000:
-        return re_error('/error/25')
+        curs.execute(db_change('select data from other where name = "count_all_title"'))
+        if int(curs.fetchall()[0][0]) > 30000:
+            return re_error('/error/25')
 
-    div = '<ul class="inside_ul">'
+        div = '<ul class="inside_ul">'
 
-    curs.execute(db_change("select distinct title, link from back where type = 'no' order by title asc limit ?, 50"), [sql_num])
-    data_list = curs.fetchall()
-    for data in data_list:
-        div += '' + \
-            '<li>' + \
-                '<a id="not_thing" href="/w/' + url_pas(data[0]) + '">' + html.escape(data[0]) + '</a> ' + \
-                '<a href="/w/' + url_pas(data[1]) + '">(' + html.escape(data[1]) + ')</a>' + \
-            '</li>' + \
-        ''
+        curs.execute(db_change("select distinct title, link from back where type = 'no' order by title asc limit ?, 50"), [sql_num])
+        data_list = curs.fetchall()
+        for data in data_list:
+            div += '' + \
+                '<li>' + \
+                    '<a id="not_thing" href="/w/' + url_pas(data[0]) + '">' + html.escape(data[0]) + '</a> ' + \
+                    '<a href="/w/' + url_pas(data[1]) + '">(' + html.escape(data[1]) + ')</a>' + \
+                '</li>' + \
+            ''
 
-    div += '</ul>' + next_fix('/please?num=', num, data_list)
+        div += '</ul>' + next_fix('/please?num=', num, data_list)
 
-    return easy_minify(flask.render_template(skin_check(),
-        imp = [load_lang('need_document'), wiki_set(), wiki_custom(), wiki_css([0, 0])],
-        data = div,
-        menu = [['other', load_lang('return')]]
-    ))
+        return easy_minify(flask.render_template(skin_check(),
+            imp = [load_lang('need_document'), wiki_set(), wiki_custom(), wiki_css([0, 0])],
+            data = div,
+            menu = [['other', load_lang('return')]]
+        ))

+ 60 - 59
route/list_title_index.py

@@ -1,78 +1,79 @@
 from .tool.func import *
 
-def list_title_index_2(conn):
-    curs = conn.cursor()
+def list_title_index_2():
+    with get_db_connect() as conn:
+        curs = conn.cursor()
 
-    page = int(number_check(flask.request.args.get('page', '1')))
-    num = int(number_check(flask.request.args.get('num', '100')))
-    sql_num = (page * num - num) if page * num > 0 else 0
+        page = int(number_check(flask.request.args.get('page', '1')))
+        num = int(number_check(flask.request.args.get('num', '100')))
+        sql_num = (page * num - num) if page * num > 0 else 0
 
-    all_list = sql_num + 1
+        all_list = sql_num + 1
 
-    if num > 1000:
-        return re_error('/error/3')
+        if num > 1000:
+            return re_error('/error/3')
 
-    data = '<a href="/title_index?num=250">(250)</a> <a href="/title_index?num=500">(500)</a> <a href="/title_index?num=1000">(1000)</a>'
+        data = '<a href="/title_index?num=250">(250)</a> <a href="/title_index?num=500">(500)</a> <a href="/title_index?num=1000">(1000)</a>'
 
-    curs.execute(db_change("select title from data order by title asc limit ?, ?"), [sql_num, num])
-    title_list = curs.fetchall()
-    if title_list:
-        data += '<hr class="main_hr"><ul class="inside_ul">'
+        curs.execute(db_change("select title from data order by title asc limit ?, ?"), [sql_num, num])
+        title_list = curs.fetchall()
+        if title_list:
+            data += '<hr class="main_hr"><ul class="inside_ul">'
 
-    for list_data in title_list:
-        data += '<li>' + str(all_list) + '. <a href="/w/' + url_pas(list_data[0]) + '">' + html.escape(list_data[0]) + '</a></li>'
-        all_list += 1
+        for list_data in title_list:
+            data += '<li>' + str(all_list) + '. <a href="/w/' + url_pas(list_data[0]) + '">' + html.escape(list_data[0]) + '</a></li>'
+            all_list += 1
 
-    if page == 1:
-        count_end = []
+        if page == 1:
+            count_end = []
 
-        curs.execute(db_change('select data from other where name = "count_all_title"'))
-        all_title = curs.fetchall()
-        if int(all_title[0][0]) < 30000:
-            curs.execute(db_change("select count(*) from data"))
-            count = curs.fetchall()
-            if count:
-                count_end += [count[0][0]]
-            else:
-                count_end += [0]
-
-            sql_list = ['category:', 'user:', 'file:']
-            for sql in sql_list:
-                curs.execute(db_change("select count(*) from data where title like ?"), [sql + '%'])
+            curs.execute(db_change('select data from other where name = "count_all_title"'))
+            all_title = curs.fetchall()
+            if int(all_title[0][0]) < 30000:
+                curs.execute(db_change("select count(*) from data"))
                 count = curs.fetchall()
                 if count:
                     count_end += [count[0][0]]
                 else:
                     count_end += [0]
 
-            count_end += [count_end[0] - count_end[1]  - count_end[2]  - count_end[3]]
+                sql_list = ['category:', 'user:', 'file:']
+                for sql in sql_list:
+                    curs.execute(db_change("select count(*) from data where title like ?"), [sql + '%'])
+                    count = curs.fetchall()
+                    if count:
+                        count_end += [count[0][0]]
+                    else:
+                        count_end += [0]
 
-            data += '''
-                </ul>
-                <hr class="main_hr">
-                <ul class="inside_ul">
-                    <li>''' + load_lang('all') + ' : ' + str(count_end[0]) + '''</li>
-                </ul>
-                <hr class="main_hr">
-                <ul class="inside_ul">
-                    <li>''' + load_lang('category') + ' : ' + str(count_end[1]) + '''</li>
-                    <li>''' + load_lang('user_document') + ' : ' + str(count_end[2]) + '''</li>
-                    <li>''' + load_lang('file') + ' : ' + str(count_end[3]) + '''</li>
-                    <li>''' + load_lang('other') + ' : ' + str(count_end[4]) + '''</li>
-            '''
-        else:
-            data += '''
-                </ul>
-                <hr class="main_hr">
-                <ul class="inside_ul">
-                    <li>''' + load_lang('all') + ' : ' + all_title[0][0] + '''</li>
-            '''
+                count_end += [count_end[0] - count_end[1]  - count_end[2]  - count_end[3]]
+
+                data += '''
+                    </ul>
+                    <hr class="main_hr">
+                    <ul class="inside_ul">
+                        <li>''' + load_lang('all') + ' : ' + str(count_end[0]) + '''</li>
+                    </ul>
+                    <hr class="main_hr">
+                    <ul class="inside_ul">
+                        <li>''' + load_lang('category') + ' : ' + str(count_end[1]) + '''</li>
+                        <li>''' + load_lang('user_document') + ' : ' + str(count_end[2]) + '''</li>
+                        <li>''' + load_lang('file') + ' : ' + str(count_end[3]) + '''</li>
+                        <li>''' + load_lang('other') + ' : ' + str(count_end[4]) + '''</li>
+                '''
+            else:
+                data += '''
+                    </ul>
+                    <hr class="main_hr">
+                    <ul class="inside_ul">
+                        <li>''' + load_lang('all') + ' : ' + all_title[0][0] + '''</li>
+                '''
 
-    data += '</ul>' + next_fix('/title_index?num=' + str(num) + '&page=', page, title_list, num)
-    sub = ' (' + str(num) + ')'
+        data += '</ul>' + next_fix('/title_index?num=' + str(num) + '&page=', page, title_list, num)
+        sub = ' (' + str(num) + ')'
 
-    return easy_minify(flask.render_template(skin_check(),
-        imp = [load_lang('all_document_list'), wiki_set(), wiki_custom(), wiki_css([sub, 0])],
-        data = data,
-        menu = [['other', load_lang('return')]]
-    ))
+        return easy_minify(flask.render_template(skin_check(),
+            imp = [load_lang('all_document_list'), wiki_set(), wiki_custom(), wiki_css([sub, 0])],
+            data = data,
+            menu = [['other', load_lang('return')]]
+        ))

+ 20 - 19
route/list_user.py

@@ -1,26 +1,27 @@
 from .tool.func import *
 
-def list_user_2(conn):
-    curs = conn.cursor()
+def list_user_2():
+    with get_db_connect() as conn:
+        curs = conn.cursor()
 
-    num = int(number_check(flask.request.args.get('num', '1')))
-    sql_num = (num * 50 - 50) if num * 50 > 0 else 0
+        num = int(number_check(flask.request.args.get('num', '1')))
+        sql_num = (num * 50 - 50) if num * 50 > 0 else 0
 
-    list_data = '<ul class="inside_ul">'
+        list_data = '<ul class="inside_ul">'
 
-    curs.execute(db_change("select id, data from user_set where name = 'date' order by data desc limit ?, 50"), [sql_num])
-    user_list = curs.fetchall()
-    for data in user_list:
-        list_data += '' + \
-            '<li>' + \
-                ip_pas(data[0]) + (' (' + data[1] + ')' if data[1] != '' else '') + \
-            '</li>' + \
-        ''
+        curs.execute(db_change("select id, data from user_set where name = 'date' order by data desc limit ?, 50"), [sql_num])
+        user_list = curs.fetchall()
+        for data in user_list:
+            list_data += '' + \
+                '<li>' + \
+                    ip_pas(data[0]) + (' (' + data[1] + ')' if data[1] != '' else '') + \
+                '</li>' + \
+            ''
 
-    list_data += '</ul>' + next_fix('/user_log?num=', num, user_list)
+        list_data += '</ul>' + next_fix('/user_log?num=', num, user_list)
 
-    return easy_minify(flask.render_template(skin_check(),
-        imp = [load_lang('member_list'), wiki_set(), wiki_custom(), wiki_css([0, 0])],
-        data = list_data,
-        menu = [['other', load_lang('return')]]
-    ))
+        return easy_minify(flask.render_template(skin_check(),
+            imp = [load_lang('member_list'), wiki_set(), wiki_custom(), wiki_css([0, 0])],
+            data = list_data,
+            menu = [['other', load_lang('return')]]
+        ))

+ 11 - 10
route/login_find.py

@@ -1,13 +1,14 @@
 from .tool.func import *
 
 def login_find():
-    return easy_minify(flask.render_template(skin_check(),
-        imp = [load_lang('password_search'), wiki_set(), wiki_custom(), wiki_css([0, 0])],
-        data = '''
-            <ul class="inside_ul">
-                <li><a href="/login/find/email">''' + load_lang('email') + '''</a></li>
-                <li><a href="/login/find/key">''' + load_lang('key') + '''</a></li>
-            </ul>
-        ''',
-        menu = [['user', load_lang('return')]]
-    ))
+    with get_db_connect() as conn:
+        return easy_minify(flask.render_template(skin_check(),
+            imp = [load_lang('password_search'), wiki_set(), wiki_custom(), wiki_css([0, 0])],
+            data = '''
+                <ul class="inside_ul">
+                    <li><a href="/login/find/email">''' + load_lang('email') + '''</a></li>
+                    <li><a href="/login/find/key">''' + load_lang('key') + '''</a></li>
+                </ul>
+            ''',
+            menu = [['user', load_lang('return')]]
+        ))

+ 60 - 59
route/login_login.py

@@ -1,72 +1,73 @@
 from .tool.func import *
 
-def login_login_2(conn):
-    curs = conn.cursor()
+def login_login_2():
+    with get_db_connect() as conn:
+        curs = conn.cursor()
 
-    ip = ip_check()
-    if ip_or_user(ip) == 0:
-        return redirect('/user')
+        ip = ip_check()
+        if ip_or_user(ip) == 0:
+            return redirect('/user')
 
-    if ban_check(None, 'login') == 1:
-        return re_error('/ban')
+        if ban_check(None, 'login') == 1:
+            return re_error('/ban')
 
-    if flask.request.method == 'POST':
-        if captcha_post(flask.request.form.get('g-recaptcha-response', flask.request.form.get('g-recaptcha', ''))) == 1:
-            return re_error('/error/13')
-        else:
-            captcha_post('', 0)
+        if flask.request.method == 'POST':
+            if captcha_post(flask.request.form.get('g-recaptcha-response', flask.request.form.get('g-recaptcha', ''))) == 1:
+                return re_error('/error/13')
+            else:
+                captcha_post('', 0)
 
-        user_agent = flask.request.headers.get('User-Agent', '')
-        user_id = flask.request.form.get('id', '')
-        user_data = {}
+            user_agent = flask.request.headers.get('User-Agent', '')
+            user_id = flask.request.form.get('id', '')
+            user_data = {}
 
-        curs.execute(db_change(
-            'select name, data from user_set where id = ? and name = "pw" or name = "encode"'
-        ), [user_id])
-        sql_data = curs.fetchall()
-        if not sql_data:
-            return re_error('/error/2')
+            curs.execute(db_change(
+                'select name, data from user_set where id = ? and name = "pw" or name = "encode"'
+            ), [user_id])
+            sql_data = curs.fetchall()
+            if not sql_data:
+                return re_error('/error/2')
 
-        for i in sql_data:
-            user_data[i[0]] = i[1]
-                
-        if len(user_data) < 2:
-            return re_error('/error/2')
+            for i in sql_data:
+                user_data[i[0]] = i[1]
 
-        if pw_check(
-            flask.request.form.get('pw', ''),
-            user_data['pw'],
-            user_data['encode'],
-            user_id
-        ) != 1:
-            return re_error('/error/10')
+            if len(user_data) < 2:
+                return re_error('/error/2')
 
-        curs.execute(db_change('select data from user_set where name = "2fa" and id = ?'), [user_id])
-        fa_data = curs.fetchall()
-        if fa_data and fa_data[0][0] != '':
-            flask.session['login_id'] = user_id
+            if pw_check(
+                flask.request.form.get('pw', ''),
+                user_data['pw'],
+                user_data['encode'],
+                user_id
+            ) != 1:
+                return re_error('/error/10')
 
-            return redirect('/login/2fa')
-        else:
-            flask.session['id'] = user_id
+            curs.execute(db_change('select data from user_set where name = "2fa" and id = ?'), [user_id])
+            fa_data = curs.fetchall()
+            if fa_data and fa_data[0][0] != '':
+                flask.session['login_id'] = user_id
 
-            ua_plus(user_id, ip, user_agent, get_time())
-            conn.commit()
+                return redirect('/login/2fa')
+            else:
+                flask.session['id'] = user_id
 
-            return redirect('/user')
-    else:
-        return easy_minify(flask.render_template(skin_check(),
-            imp = [load_lang('login'), wiki_set(), wiki_custom(), wiki_css([0, 0])],
-            data =  '''
-                    <form method="post">
-                        <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">
-                        ''' + captcha_get() + '''
-                        <button type="submit">''' + load_lang('login') + '''</button>
-                        ''' + http_warning() + '''
-                    </form>
-                    ''',
-            menu = [['user', load_lang('return')]]
-        ))
+                ua_plus(user_id, ip, user_agent, get_time())
+                conn.commit()
+
+                return redirect('/user')
+        else:
+            return easy_minify(flask.render_template(skin_check(),
+                imp = [load_lang('login'), wiki_set(), wiki_custom(), wiki_css([0, 0])],
+                data =  '''
+                        <form method="post">
+                            <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">
+                            ''' + captcha_get() + '''
+                            <button type="submit">''' + load_lang('login') + '''</button>
+                            ''' + http_warning() + '''
+                        </form>
+                        ''',
+                menu = [['user', load_lang('return')]]
+            ))

+ 58 - 57
route/login_login_2fa.py

@@ -1,70 +1,71 @@
 from .tool.func import *
 
-def login_login_2fa_2(conn):
-    curs = conn.cursor()
+def login_login_2fa_2():
+    with get_db_connect() as conn:
+        curs = conn.cursor()
 
-    # email 2fa
-    # pw 2fa
-    # q_a 2fa
-    if not (flask.session and 'login_id' in flask.session):
-        return redirect('/user')
+        # email 2fa
+        # pw 2fa
+        # q_a 2fa
+        if not (flask.session and 'login_id' in flask.session):
+            return redirect('/user')
 
-    ip = ip_check()
-    if ip_or_user(ip) == 0:
-        return redirect('/user')
+        ip = ip_check()
+        if ip_or_user(ip) == 0:
+            return redirect('/user')
 
-    if ban_check(None, 'login') == 1:
-        return re_error('/ban')
+        if ban_check(None, 'login') == 1:
+            return re_error('/ban')
 
-    if flask.request.method == 'POST':
-        if captcha_post(flask.request.form.get('g-recaptcha-response', flask.request.form.get('g-recaptcha', ''))) == 1:
-            return re_error('/error/13')
-        else:
-            captcha_post('', 0)
+        if flask.request.method == 'POST':
+            if captcha_post(flask.request.form.get('g-recaptcha-response', flask.request.form.get('g-recaptcha', ''))) == 1:
+                return re_error('/error/13')
+            else:
+                captcha_post('', 0)
 
-        user_agent = flask.request.headers.get('User-Agent', '')
-        user_id = flask.session['login_id']
+            user_agent = flask.request.headers.get('User-Agent', '')
+            user_id = flask.session['login_id']
 
-        curs.execute(db_change('select data from user_set where name = "2fa_pw" and id = ?'), [user_id])
-        user_1 = curs.fetchall()
-        if user_1:
-            curs.execute(db_change('select data from user_set where name = "2fa_pw_encode" and id = ?'), [user_id])
-            user_1 = user_1[0][0]
-            user_2 = curs.fetchall()[0][0]
+            curs.execute(db_change('select data from user_set where name = "2fa_pw" and id = ?'), [user_id])
+            user_1 = curs.fetchall()
+            if user_1:
+                curs.execute(db_change('select data from user_set where name = "2fa_pw_encode" and id = ?'), [user_id])
+                user_1 = user_1[0][0]
+                user_2 = curs.fetchall()[0][0]
 
-            pw_check_d = pw_check(
-                flask.request.form.get('pw', ''),
-                user_1,
-                user_2,
-                user_id
-            )
-            if pw_check_d != 1:
-                return re_error('/error/10')
+                pw_check_d = pw_check(
+                    flask.request.form.get('pw', ''),
+                    user_1,
+                    user_2,
+                    user_id
+                )
+                if pw_check_d != 1:
+                    return re_error('/error/10')
 
-        flask.session['id'] = user_id
+            flask.session['id'] = user_id
 
-        ua_plus(
-            user_id, 
-            ip, 
-            user_agent, 
-            get_time()
-        )
-        conn.commit()
+            ua_plus(
+                user_id, 
+                ip, 
+                user_agent, 
+                get_time()
+            )
+            conn.commit()
 
-        flask.session.pop('b_id', None)
+            flask.session.pop('b_id', None)
 
-        return redirect('/user')
-    else:
-        return easy_minify(flask.render_template(skin_check(),
-            imp = [load_lang('login'), wiki_set(), wiki_custom(), wiki_css([0, 0])],
-            data =  '''
-                    <form method="post">
-                        <input placeholder="''' + load_lang('2fa_password') + '''" name="pw" type="password">
-                        <hr class="main_hr">
-                        ''' + captcha_get() + '''
-                        <button type="submit">''' + load_lang('login') + '''</button>
-                        ''' + http_warning() + '''
-                    </form>
-                    ''',
-            menu = [['user', load_lang('return')]]
-        ))
+            return redirect('/user')
+        else:
+            return easy_minify(flask.render_template(skin_check(),
+                imp = [load_lang('login'), wiki_set(), wiki_custom(), wiki_css([0, 0])],
+                data =  '''
+                        <form method="post">
+                            <input placeholder="''' + load_lang('2fa_password') + '''" name="pw" type="password">
+                            <hr class="main_hr">
+                            ''' + captcha_get() + '''
+                            <button type="submit">''' + load_lang('login') + '''</button>
+                            ''' + http_warning() + '''
+                        </form>
+                        ''',
+                menu = [['user', load_lang('return')]]
+            ))

+ 53 - 52
route/login_login_2fa_email.py

@@ -1,65 +1,66 @@
 from .tool.func import *
 
-def login_login_2fa_email_2(conn):
-    curs = conn.cursor()
+def login_login_2fa_email_2():
+    with get_db_connect() as conn:
+        curs = conn.cursor()
 
-    # email 2fa
-    # pw 2fa
-    # q_a 2fa
-    if not (flask.session and 'login_id' in flask.session):
-        return redirect('/user')
+        # email 2fa
+        # pw 2fa
+        # q_a 2fa
+        if not (flask.session and 'login_id' in flask.session):
+            return redirect('/user')
 
-    ip = ip_check()
-    if ip_or_user(ip) == 0:
-        return redirect('/user')
+        ip = ip_check()
+        if ip_or_user(ip) == 0:
+            return redirect('/user')
 
-    if ban_check(None, 'login') == 1:
-        return re_error('/ban')
+        if ban_check(None, 'login') == 1:
+            return re_error('/ban')
 
-    if flask.request.method == 'POST':
-        if captcha_post(flask.request.form.get('g-recaptcha-response', flask.request.form.get('g-recaptcha', ''))) == 1:
-            return re_error('/error/13')
-        else:
-            captcha_post('', 0)
+        if flask.request.method == 'POST':
+            if captcha_post(flask.request.form.get('g-recaptcha-response', flask.request.form.get('g-recaptcha', ''))) == 1:
+                return re_error('/error/13')
+            else:
+                captcha_post('', 0)
 
-        user_agent = flask.request.headers.get('User-Agent', '')
-        user_id = flask.session['b_id']
+            user_agent = flask.request.headers.get('User-Agent', '')
+            user_id = flask.session['b_id']
 
-        curs.execute(db_change('select data from user_set where name = "2fa_pw" and id = ?'), [user_id])
-        user_1 = curs.fetchall()
-        if user_1:
-            curs.execute(db_change('select data from user_set where name = "2fa_pw_encode" and id = ?'), [user_id])
-            user_1 = user_1[0][0]
-            user_2 = curs.fetchall()[0][0]
+            curs.execute(db_change('select data from user_set where name = "2fa_pw" and id = ?'), [user_id])
+            user_1 = curs.fetchall()
+            if user_1:
+                curs.execute(db_change('select data from user_set where name = "2fa_pw_encode" and id = ?'), [user_id])
+                user_1 = user_1[0][0]
+                user_2 = curs.fetchall()[0][0]
 
-            pw_check_d = pw_check(
-                flask.request.form.get('pw', ''),
-                user_1,
-                user_2,
-                user_id
-            )
-            if pw_check_d != 1:
-                return re_error('/error/10')
+                pw_check_d = pw_check(
+                    flask.request.form.get('pw', ''),
+                    user_1,
+                    user_2,
+                    user_id
+                )
+                if pw_check_d != 1:
+                    return re_error('/error/10')
 
-        flask.session['id'] = user_id
+            flask.session['id'] = user_id
 
-        ua_plus(user_id, ip, user_agent, get_time())
-        conn.commit()
+            ua_plus(user_id, ip, user_agent, get_time())
+            conn.commit()
 
-        flask.session.pop('b_id', None)
+            flask.session.pop('b_id', None)
 
-        return redirect('/user')
-    else:
-        return easy_minify(flask.render_template(skin_check(),
-            imp = [load_lang('login'), wiki_set(), wiki_custom(), wiki_css([0, 0])],
-            data =  '''
-                    <form method="post">
-                        <input placeholder="''' + load_lang('2fa_password') + '''" name="pw" type="password">
-                        <hr class=\"main_hr\">
-                        ''' + captcha_get() + '''
-                        <button type="submit">''' + load_lang('login') + '''</button>
-                        ''' + http_warning() + '''
-                    </form>
-                    ''',
-            menu = [['user', load_lang('return')]]
-        ))
+            return redirect('/user')
+        else:
+            return easy_minify(flask.render_template(skin_check(),
+                imp = [load_lang('login'), wiki_set(), wiki_custom(), wiki_css([0, 0])],
+                data =  '''
+                        <form method="post">
+                            <input placeholder="''' + load_lang('2fa_password') + '''" name="pw" type="password">
+                            <hr class=\"main_hr\">
+                            ''' + captcha_get() + '''
+                            <button type="submit">''' + load_lang('login') + '''</button>
+                            ''' + http_warning() + '''
+                        </form>
+                        ''',
+                menu = [['user', load_lang('return')]]
+            ))

+ 4 - 3
route/login_logout.py

@@ -1,7 +1,8 @@
 from .tool.func import *
 
 def login_logout():
-    flask.session.pop('state', None)
-    flask.session.pop('id', None)
+    with get_db_connect() as conn:
+        flask.session.pop('state', None)
+        flask.session.pop('id', None)
 
-    return redirect('/user')
+        return redirect('/user')

+ 120 - 113
route/login_register.py

@@ -1,122 +1,129 @@
 from .tool.func import *
 
-def login_register_2(conn):
-    curs = conn.cursor()
+def login_register_2():
+    with get_db_connect() as conn:
+        curs = conn.cursor()
 
-    if ban_check(None, 'login') == 1:
-        return re_error('/ban')
+        if ban_check(None, 'login') == 1:
+            return re_error('/ban')
 
-    ip = ip_check()
-    admin = admin_check()
-    if admin != 1 and ip_or_user(ip) == 0:
-        return redirect('/user')
+        ip = ip_check()
+        admin = admin_check()
+        if admin != 1 and ip_or_user(ip) == 0:
+            return redirect('/user')
 
-    if admin != 1:
-        curs.execute(db_change('select data from other where name = "reg"'))
-        set_d = curs.fetchall()
-        if set_d and set_d[0][0] == 'on':
-            return re_error('/ban')
+        if admin != 1:
+            curs.execute(db_change('select data from other where name = "reg"'))
+            set_d = curs.fetchall()
+            if set_d and set_d[0][0] == 'on':
+                return re_error('/ban')
 
-    if flask.request.method == 'POST':
-        # 리캡차
-        if captcha_post(flask.request.form.get('g-recaptcha-response', flask.request.form.get('g-recaptcha', ''))) == 1:
-            return re_error('/error/13')
-        else:
-            captcha_post('', 0)
-
-        # 아이디 비밀번호 검증 파트
-        user_id = flask.request.form.get('id', '')
-        user_pw = flask.request.form.get('pw', '')
-        user_repeat = flask.request.form.get('pw2', '')
-        if user_id == '' or user_pw == '':
-            return re_error('/error/27')
-
-        if user_pw != user_repeat:
-            return re_error('/error/20')
-
-        if re.search(r'(?:[^A-Za-zㄱ-힣0-9])', user_id):
-            return re_error('/error/8')
-
-        curs.execute(db_change('select html from html_filter where kind = "name"'))
-        set_d = curs.fetchall()
-        for i in set_d:
-            check_r = re.compile(i[0], re.I)
-            if check_r.search(user_id):
+        if flask.request.method == 'POST':
+            # 리캡차
+            if captcha_post(flask.request.form.get('g-recaptcha-response', flask.request.form.get('g-recaptcha', ''))) == 1:
+                return re_error('/error/13')
+            else:
+                captcha_post('', 0)
+
+            user_id = flask.request.form.get('id', '')
+            user_pw = flask.request.form.get('pw', '')
+            user_repeat = flask.request.form.get('pw2', '')
+
+            # PW 검증
+            if user_id == '' or user_pw == '':
+                return re_error('/error/27')
+
+            if user_pw != user_repeat:
+                return re_error('/error/20')
+
+            # PW 길이 제한
+            curs.execute(db_change("select data from other where name = 'password_min_length'"))
+            db_data = curs.fetchall()
+            if db_data and db_data[0][0] != '':
+                password_min_length = int(number_check(db_data[0][0]))
+                if password_min_length > len(user_pw):
+                    return re_error('/error/40')
+
+            # ID 글자 확인
+            if re.search(r'(?:[^A-Za-zㄱ-힣0-9])', user_id):
                 return re_error('/error/8')
 
-        if len(user_id) > 32:
-            return re_error('/error/7')
+            # ID 필터
+            curs.execute(db_change('select html from html_filter where kind = "name"'))
+            set_d = curs.fetchall()
+            for i in set_d:
+                check_r = re.compile(i[0], re.I)
+                if check_r.search(user_id):
+                    return re_error('/error/8')
 
-        curs.execute(db_change("select id from user_set where id = ?"), [user_id])
-        if curs.fetchall():
-            return re_error('/error/6')
-        
-        if admin != 1:
-            # 이메일 필요시 /register/email로 발송
-            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['reg_id'] = user_id
-                flask.session['reg_pw'] = user_pw
-
-                return redirect('/register/email')
-            
-            # 가입 승인 필요시 /register/submit으로 발송
-            curs.execute(db_change('select data from other where name = "requires_approval"'))
-            sql_data = curs.fetchall()
-            if sql_data and sql_data[0][0] != '':
-                flask.session['submit_id'] = user_id
-                flask.session['submit_pw'] = user_pw
-                
-                return redirect('/register/submit')
-        
-        # 전부 아니면 바로 가입 후 /login으로 발송
-        add_user(user_id, user_pw)
-        
-        return redirect('/login')
-    else:
-        curs.execute(db_change('select data from other where name = "contract"'))
-        data = curs.fetchall()
-        contract = (data[0][0] + '<hr class="main_hr">') if data and data[0][0] != '' else ''
-                
-        return easy_minify(flask.render_template(skin_check(),
-            imp = [load_lang('register'), wiki_set(), wiki_custom(), wiki_css([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() + '''
-                    
-                    <!--
-                    <a href="" id="oauth_google">(Google)</a>     
-                    <hr class="main_hr">
-                    -->
-                    
-                    <button type="submit">''' + load_lang('save') + '''</button>
-                    
-                    ''' + http_warning() + '''
-                </form>
-                <script>
-                    document.getElementById('oauth_google').href = '' +
-                        'https://accounts.google.com/o/oauth2/auth' +
-                        '?client_id=ID' +
-                        '&redirect_uri=' + window.location.origin +
-                        '&response_type=code' +
-                        '&scope=https://www.googleapis.com/auth/userinfo.email' +
-                        '&approval_prompt=force' +
-                        '&access_type=offline' +
-                    '';
-                </script>
-            ''',
-            menu = [['user', load_lang('return')]]
-        ))
+            # ID 길이 제한 (32글자)
+            if len(user_id) > 32:
+                return re_error('/error/7')
+
+            # 중복 확인
+            curs.execute(db_change("select id from user_set where id = ?"), [user_id])
+            if curs.fetchall():
+                return re_error('/error/6')
+
+            if admin != 1:
+                # 이메일 필요시 /register/email로 발송
+                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['reg_id'] = user_id
+                    flask.session['reg_pw'] = user_pw
+
+                    return redirect('/register/email')
+
+                # 가입 승인 필요시 /register/submit으로 발송
+                curs.execute(db_change('select data from other where name = "requires_approval"'))
+                sql_data = curs.fetchall()
+                if sql_data and sql_data[0][0] != '':
+                    flask.session['submit_id'] = user_id
+                    flask.session['submit_pw'] = user_pw
+
+                    return redirect('/register/submit')
+
+            # 전부 아니면 바로 가입 후 /login으로 발송
+            add_user(user_id, user_pw)
+
+            conn.commit()
+
+            return redirect('/login')
+        else:
+            curs.execute(db_change('select data from other where name = "contract"'))
+            data = curs.fetchall()
+            contract = (data[0][0] + '<hr class="main_hr">') if data and data[0][0] != '' else ''
+
+            curs.execute(db_change("select data from other where name = 'password_min_length'"))
+            db_data = curs.fetchall()
+            if db_data and db_data[0][0] != '':
+                password_min_length = ' (' + load_lang('password_min_length') + ' : ' + db_data[0][0] + ')'
+            else:
+                password_min_length = ''
+
+            return easy_minify(flask.render_template(skin_check(),
+                imp = [load_lang('register'), wiki_set(), wiki_custom(), wiki_css([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') + password_min_length + '''" 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_warning() + '''
+                    </form>
+                ''',
+                menu = [['user', load_lang('return')]]
+            ))

+ 56 - 55
route/login_register_email.py

@@ -1,66 +1,67 @@
 from .tool.func import *
 
-def login_register_email_2(conn):
-    curs = conn.cursor()
-    
-    if not 'reg_id' in flask.session:
-        return redirect('/register')
-    
-    if flask.request.method == 'POST':
-        flask.session['reg_key'] = load_random_key(32)
+def login_register_email_2():
+    with get_db_connect() as conn:
+        curs = conn.cursor()
 
-        user_email = re.sub(r'\\', '', flask.request.form.get('email', ''))
-        email_data = re.search(r'@([^@]+)$', user_email)
-        if email_data:
-            email_data = email_data.group(1)
-            
-            curs.execute(db_change(
-                "select html from html_filter where html = ? and kind = 'email'"
-            ), [email_data])
-            if not curs.fetchall():                
-                return redirect('/email_filter')
+        if not 'reg_id' in flask.session:
+            return redirect('/register')
 
-        curs.execute(db_change('select data from other where name = "email_title"'))
-        sql_d = curs.fetchall()
-        if sql_d and sql_d[0][0] != '':
-            t_text = html.escape(sql_d[0][0])
-        else:
-            t_text = wiki_set()[0] + ' key'
+        if flask.request.method == 'POST':
+            flask.session['reg_key'] = load_random_key(32)
 
-        curs.execute(db_change('select data from other where name = "email_text"'))
-        sql_d = curs.fetchall()
-        if sql_d and sql_d[0][0] != '':
-            i_text = html.escape(sql_d[0][0]) + '\n\nKey : ' + str(flask.session.get('reg_key'))
-        else:
-            i_text = 'Key : ' + str(flask.session.get('reg_key'))
-        
+            user_email = re.sub(r'\\', '', flask.request.form.get('email', ''))
+            email_data = re.search(r'@([^@]+)$', user_email)
+            if email_data:
+                email_data = email_data.group(1)
+
+                curs.execute(db_change(
+                    "select html from html_filter where html = ? and kind = 'email'"
+                ), [email_data])
+                if not curs.fetchall():                
+                    return redirect('/email_filter')
+
+            curs.execute(db_change('select data from other where name = "email_title"'))
+            sql_d = curs.fetchall()
+            if sql_d and sql_d[0][0] != '':
+                t_text = html.escape(sql_d[0][0])
+            else:
+                t_text = wiki_set()[0] + ' key'
 
-        curs.execute(db_change('select id from user_set where name = "email" and data = ?'), [user_email])
-        if curs.fetchall():
-            return re_error('/error/35')
+            curs.execute(db_change('select data from other where name = "email_text"'))
+            sql_d = curs.fetchall()
+            if sql_d and sql_d[0][0] != '':
+                i_text = html.escape(sql_d[0][0]) + '\n\nKey : ' + str(flask.session.get('reg_key'))
+            else:
+                i_text = 'Key : ' + str(flask.session.get('reg_key'))
 
-        if send_email(user_email, t_text, i_text) == 0:
-            return re_error('/error/18')
 
-        flask.session['reg_email'] = user_email
+            curs.execute(db_change('select id from user_set where name = "email" and data = ?'), [user_email])
+            if curs.fetchall():
+                return re_error('/error/35')
 
-        return redirect('/register/email/check')
-    else:
-        curs.execute(db_change('select data from other where name = "email_insert_text"'))
-        sql_d = curs.fetchall()
-        b_text = (sql_d[0][0] + '<hr class="main_hr">') if sql_d and sql_d[0][0] != '' else ''
+            if send_email(user_email, t_text, i_text) == 0:
+                return re_error('/error/18')
+
+            flask.session['reg_email'] = user_email
+
+            return redirect('/register/email/check')
+        else:
+            curs.execute(db_change('select data from other where name = "email_insert_text"'))
+            sql_d = curs.fetchall()
+            b_text = (sql_d[0][0] + '<hr class="main_hr">') if sql_d and sql_d[0][0] != '' else ''
 
-        return easy_minify(flask.render_template(skin_check(),
-            imp = [load_lang('email'), wiki_set(), wiki_custom(), wiki_css([0, 0])],
-            data = '''
-                <a href="/email_filter">(''' + load_lang('email_filter_list') + ''')</a>
-                <hr class="main_hr">
-                ''' + b_text + '''
-                <form method="post">
-                    <input placeholder="''' + load_lang('email') + '''" name="email" type="text">
+            return easy_minify(flask.render_template(skin_check(),
+                imp = [load_lang('email'), wiki_set(), wiki_custom(), wiki_css([0, 0])],
+                data = '''
+                    <a href="/email_filter">(''' + load_lang('email_filter_list') + ''')</a>
                     <hr class="main_hr">
-                    <button type="submit">''' + load_lang('save') + '''</button>
-                </form>
-            ''',
-            menu = [['user', load_lang('return')]]
-        ))
+                    ''' + b_text + '''
+                    <form method="post">
+                        <input placeholder="''' + load_lang('email') + '''" name="email" type="text">
+                        <hr class="main_hr">
+                        <button type="submit">''' + load_lang('save') + '''</button>
+                    </form>
+                ''',
+                menu = [['user', load_lang('return')]]
+            ))

+ 43 - 42
route/login_register_email_check.py

@@ -1,47 +1,48 @@
 from .tool.func import *
 
-def login_register_email_check_2(conn):
-    curs = conn.cursor()
+def login_register_email_check_2():
+    with get_db_connect() as conn:
+        curs = conn.cursor()
 
-    if not 'reg_email' in flask.session:
-        return redirect('/register')
-    
-    if  flask.request.method == 'POST':
-        input_key = flask.request.form.get('key', '')
-
-        if flask.session['reg_key'] != input_key:
+        if not 'reg_email' in flask.session:
             return redirect('/register')
 
-        curs.execute(db_change('select data from other where name = "requires_approval"'))
-        sql_data = curs.fetchall()
-        if sql_data and sql_data[0][0] != '':
-            flask.session['submit_id'] = flask.session['reg_id']
-            flask.session['submit_pw'] = flask.session['reg_pw']
-            flask.session['submit_email'] = flask.session['reg_email']
-            
-            return redirect('/register/submit')
-        
-        add_user(
-            flask.session['reg_id'],
-            flask.session['reg_pw'],
-            flask.session['reg_email']
-        )
-
-        return redirect('/login')
-    else:
-        curs.execute(db_change('select data from other where name = "check_key_text"'))
-        sql_d = curs.fetchall()
-        b_text = (sql_d[0][0] + '<hr class="main_hr">') if sql_d and sql_d[0][0] != '' else ''
-
-        return easy_minify(flask.render_template(skin_check(),
-            imp = [load_lang('check_key'), wiki_set(), wiki_custom(), wiki_css([0, 0])],
-            data = '''
-                <form method="post">
-                    ''' + b_text + '''
-                    <input placeholder="''' + load_lang('key') + '''" name="key" type="text">
-                    <hr class="main_hr">
-                    <button type="submit">''' + load_lang('save') + '''</button>
-                </form>
-            ''',
-            menu = [['user', load_lang('return')]]
-        ))
+        if  flask.request.method == 'POST':
+            input_key = flask.request.form.get('key', '')
+
+            if flask.session['reg_key'] != input_key:
+                return redirect('/register')
+
+            curs.execute(db_change('select data from other where name = "requires_approval"'))
+            sql_data = curs.fetchall()
+            if sql_data and sql_data[0][0] != '':
+                flask.session['submit_id'] = flask.session['reg_id']
+                flask.session['submit_pw'] = flask.session['reg_pw']
+                flask.session['submit_email'] = flask.session['reg_email']
+
+                return redirect('/register/submit')
+
+            add_user(
+                flask.session['reg_id'],
+                flask.session['reg_pw'],
+                flask.session['reg_email']
+            )
+
+            return redirect('/login')
+        else:
+            curs.execute(db_change('select data from other where name = "check_key_text"'))
+            sql_d = curs.fetchall()
+            b_text = (sql_d[0][0] + '<hr class="main_hr">') if sql_d and sql_d[0][0] != '' else ''
+
+            return easy_minify(flask.render_template(skin_check(),
+                imp = [load_lang('check_key'), wiki_set(), wiki_custom(), wiki_css([0, 0])],
+                data = '''
+                    <form method="post">
+                        ''' + b_text + '''
+                        <input placeholder="''' + load_lang('key') + '''" name="key" type="text">
+                        <hr class="main_hr">
+                        <button type="submit">''' + load_lang('save') + '''</button>
+                    </form>
+                ''',
+                menu = [['user', load_lang('return')]]
+            ))

+ 56 - 57
route/login_register_submit.py

@@ -1,61 +1,60 @@
 from .tool.func import *
 
-from .tool.func import *
+def login_register_submit_2():
+    with get_db_connect() as conn:
+        curs = conn.cursor()
+
+        if not 'submit_id' in flask.session:
+            return redirect('/register')
+
+        curs.execute(db_change('select data from other where name = "approval_question"'))
+        sql_data = curs.fetchall()
+        if not sql_data:
+            return redirect('/register')
+
+        data_que = sql_data[0][0]
+
+        if flask.request.method == 'POST':
+            curs.execute(db_change('select data from other where name = "encode"'))
+            data_encode = curs.fetchall()
+            data_encode = data_encode[0][0]
+
+            user_ip = ip_check()
+            user_agent = flask.request.headers.get('User-Agent', '')
+
+            user_app_data = {}
+            user_app_data['id'] = flask.session['submit_id']
+            user_app_data['pw'] = pw_encode(flask.session['submit_pw'])
+            user_app_data['encode'] = data_encode
+            user_app_data['question'] = data_que
+            user_app_data['answer'] = flask.request.form.get('answer', '')
+
+            if 'submit_email' in flask.session:
+                user_app_data['email'] = flask.session['submit_email']
+            else:
+                user_app_data['email'] = ''
+
+            curs.execute(db_change(
+                "insert into user_set (id, name, data) values (?, ?, ?)"
+            ), [
+                flask.session['submit_id'],
+                'application',
+                json.dumps(user_app_data)
+            ])
+            conn.commit()
 
-def login_register_submit_2(conn):
-    curs = conn.cursor()
-    
-    if not 'submit_id' in flask.session:
-        return redirect('/register')
-    
-    curs.execute(db_change('select data from other where name = "approval_question"'))
-    sql_data = curs.fetchall()
-    if not sql_data:
-        return redirect('/register')
-    
-    data_que = sql_data[0][0]
-    
-    if flask.request.method == 'POST':
-        curs.execute(db_change('select data from other where name = "encode"'))
-        data_encode = curs.fetchall()
-        data_encode = data_encode[0][0]
-        
-        user_ip = ip_check()
-        user_agent = flask.request.headers.get('User-Agent', '')
-        
-        user_app_data = {}
-        user_app_data['id'] = flask.session['submit_id']
-        user_app_data['pw'] = pw_encode(flask.session['submit_pw'])
-        user_app_data['encode'] = data_encode
-        user_app_data['question'] = data_que
-        user_app_data['answer'] = flask.request.form.get('answer', '')
-        
-        if 'submit_email' in flask.session:
-            user_app_data['email'] = flask.session['submit_email']
+            return redirect('/')
         else:
-            user_app_data['email'] = ''
-            
-        curs.execute(db_change(
-            "insert into user_set (id, name, data) values (?, ?, ?)"
-        ), [
-            flask.session['submit_id'],
-            'application',
-            json.dumps(user_app_data)
-        ])
-        conn.commit()
-        
-        return redirect('/')
-    else:
-        return easy_minify(flask.render_template(skin_check(),
-            imp = [load_lang('approval_question'), wiki_set(), wiki_custom(), wiki_css([0, 0])],
-            data = '''
-                <form method="post">
-                    ''' + load_lang('approval_question') + ' : ' + data_que + '''
-                    <hr class="main_hr">
-                    <input placeholder="''' + load_lang('approval_question') + '''" name="answer">
-                    <hr class="main_hr">
-                    <button type="submit">''' + load_lang('save') + '''</button>
-                </form>
-            ''',
-            menu = [['user', load_lang('return')]]
-        ))
+            return easy_minify(flask.render_template(skin_check(),
+                imp = [load_lang('approval_question'), wiki_set(), wiki_custom(), wiki_css([0, 0])],
+                data = '''
+                    <form method="post">
+                        ''' + load_lang('approval_question') + ' : ' + data_que + '''
+                        <hr class="main_hr">
+                        <input placeholder="''' + load_lang('approval_question') + '''" name="answer">
+                        <hr class="main_hr">
+                        <button type="submit">''' + load_lang('save') + '''</button>
+                    </form>
+                ''',
+                menu = [['user', load_lang('return')]]
+            ))

+ 11 - 4
route/main_error_404.py

@@ -1,7 +1,14 @@
 from .tool.func import *
 
 def main_error_404(e = ''):
-    if os.path.exists('404.html') and flask.request.path != '/':
-        return open('404.html', encoding = 'utf8').read(), 404
-    else:
-        return redirect('/w/' + wiki_set(2))
+    with get_db_connect() as conn:
+        curs = conn.cursor()
+        
+        if os.path.exists('404.html') and flask.request.path != '/':
+            return open('404.html', encoding = 'utf8').read(), 404
+        else:
+            curs.execute(db_change('select data from other where name = "frontpage"'))
+            db_data = curs.fetchall()
+            db_data = db_data[0][0] if db_data and db_data[0][0] != '' else 'FrontPage'
+            
+            return redirect('/w/' + db_data)

+ 17 - 15
route/main_func_setting.py

@@ -1,20 +1,22 @@
 from .tool.func import *
 
 def main_func_setting():
-    li_list = [
-        ['main', load_lang('main_setting')],
-        ['phrase', load_lang('text_setting')],
-        ['robot', 'robots.txt'],
-        ['external', load_lang('ext_api_req_set')],
-        ['head', load_lang('main_head')],
-        ['body/top', load_lang('main_body')],
-        ['body/bottom', load_lang('main_bottom_body')]
-    ]
+    with get_db_connect() as conn:
+        li_list = [
+            ['main', load_lang('main_setting')],
+            ['phrase', load_lang('text_setting')],
+            ['robot', 'robots.txt'],
+            ['external', load_lang('ext_api_req_set')],
+            ['head', load_lang('main_head')],
+            ['body/top', load_lang('main_body')],
+            ['body/bottom', load_lang('main_bottom_body')],
+            ['sitemap', load_lang('sitemap_management') + ' (' + load_lang('beta') + ')']
+        ]
 
-    li_data = ''.join(['<li><a href="/setting/' + str(li[0]) + '">' + li[1] + '</a></li>' for li in li_list])
+        li_data = ''.join(['<li><a href="/setting/' + str(li[0]) + '">' + li[1] + '</a></li>' for li in li_list])
 
-    return easy_minify(flask.render_template(skin_check(),
-        imp = [load_lang('setting'), wiki_set(), wiki_custom(), wiki_css([0, 0])],
-        data = '<h2>' + load_lang('list') + '</h2><ul class="inside_ul">' + li_data + '</ul>',
-        menu = [['manager', load_lang('return')]]
-    ))
+        return easy_minify(flask.render_template(skin_check(),
+            imp = [load_lang('setting'), wiki_set(), wiki_custom(), wiki_css([0, 0])],
+            data = '<h2>' + load_lang('list') + '</h2><ul class="inside_ul">' + li_data + '</ul>',
+            menu = [['manager', load_lang('return')]]
+        ))

+ 8 - 1
route/main_func_setting_acl.py

@@ -66,31 +66,38 @@ def main_func_setting_acl():
                     <form method="post">
                         <a href="/acl/TEST#exp">(''' + load_lang('reference') + ''')</a>
                         <hr class="main_hr">
+                        
                         <span>''' + load_lang('document_acl') + '''</span> 
                         <hr class="main_hr">
                         <select ''' + disable + ''' name="edit">''' + acl_div[0] + '''</select>
                         <hr class="main_hr">
+                        
                         <span>''' + load_lang('discussion_acl') + '''</span>
                         <hr class="main_hr">
                         <select ''' + disable + ''' name="discussion">''' + acl_div[1] + '''</select>
                         <hr class="main_hr">
+                        
                         <span>''' + load_lang('upload_acl') + '''</span>
                         <hr class="main_hr">
                         <select ''' + disable + ''' name="upload_acl">''' + acl_div[2] + '''</select>
                         <hr class="main_hr">
+                        
                         <span>''' + load_lang('view_acl') + '''</span>
                         <hr class="main_hr">
                         <select ''' + disable + ''' name="all_view_acl">''' + acl_div[3] + '''</select>
                         <hr class="main_hr">
+                        
                         <span>''' + load_lang('many_upload_acl') + '''</span>
                         <hr class="main_hr">
                         <select ''' + disable + ''' name="many_upload_acl">''' + acl_div[4] + '''</select>
                         <hr class="main_hr">
+                        
                         <span>''' + load_lang('vote_acl') + '''</span>
                         <hr class="main_hr">
                         <select ''' + disable + ''' name="vote_acl">''' + acl_div[5] + '''</select>
                         <hr class="main_hr">
-                        <button id="save" type="submit">''' + load_lang('save') + '''</button>
+                        
+                        <button id="opennamu_js_save" type="submit">''' + load_lang('save') + '''</button>
                     </form>
                 ''',
                 menu = [['setting', load_lang('return')]]

+ 3 - 3
route/main_func_setting_external.py

@@ -72,7 +72,7 @@ def main_func_setting_external():
             return easy_minify(flask.render_template(skin_check(),
                 imp = [load_lang('ext_api_req_set'), wiki_set(), wiki_custom(), wiki_css([0, 0])],
                 data = '''
-                    <form method="post" id="main_set_data">
+                    <form method="post" id="opennamu_simple_render">
                         <h2>1. ''' + load_lang('captcha') + '''</h2>
                         <a href="https://www.google.com/recaptcha/">(''' + load_lang('recaptcha') + ''')</a> <a href="https://www.hcaptcha.com/">(''' + load_lang('hcaptcha') + ''')</a>
                         <hr class="main_hr">
@@ -137,9 +137,9 @@ def main_func_setting_external():
                         <hr class="main_hr">
 
                         <hr class="main_hr">
-                        <button id="save" type="submit">''' + load_lang('save') + '''</button>
+                        <button id="opennamu_js_save" type="submit">''' + load_lang('save') + '''</button>
                     </form>
-                    <script>simple_render('main_set_data');</script>
+                    <!-- JS : opennamu_do_render_simple -->
                 ''',
                 menu = [['setting', load_lang('return')]]
             ))

+ 13 - 8
route/main_func_setting_head.py

@@ -48,27 +48,31 @@ def main_func_setting_head(num, skin_name = ''):
                 title = '_body'
                 start = ''
                 plus = '''
-                    <button id="preview" type="button" onclick="load_raw_preview(\'content\', \'see_preview\')">''' + load_lang('preview') + '''</button>
+                    <button id="opennamu_js_preview" type="button" onclick="load_raw_preview(\'content\', \'opennamu_js_preview_area\')">''' + load_lang('preview') + '''</button>
                     <hr class="main_hr">
-                    <div id="see_preview"></div>
+                    <div id="opennamu_js_preview_area"></div>
                 '''
             elif num == 7:
                 curs.execute(db_change("select data from other where name = 'bottom_body'"))
                 title = '_bottom_body'
                 start = ''
                 plus = '''
-                    <button id="preview" type="button" onclick="load_raw_preview(\'content\', \'see_preview\')">''' + load_lang('preview') + '''</button>
+                    <button id="opennamu_js_preview" type="button" onclick="load_raw_preview(\'content\', \'opennamu_js_preview_area\')">''' + load_lang('preview') + '''</button>
                     <hr class="main_hr">
-                    <div id="see_preview"></div>
+                    <div id="opennamu_js_preview_area"></div>
                 '''
             else:
                 curs.execute(db_change("select data from other where name = 'head' and coverage = ?"), [skin_name])
                 title = '_head'
                 start = '' + \
-                    '<a href="?">(' + load_lang('all') + ')</a> ' + \
-                    ' '.join(['<a href="/setting/head/' + i + '">(' + i + ')</a>' for i in load_skin('', 1)]) + '''
+                    '<a href="/setting/head">(' + load_lang('all') + ')</a> ' + \
+                    ' '.join(['<a href="/setting/head/' + url_pas(i) + '">(' + html.escape(i) + ')</a>' for i in load_skin('', 1)]) + '''
                     <hr class="main_hr">
-                    <span>&lt;style&gt;CSS&lt;/style&gt;<br>&lt;script&gt;JS&lt;/script&gt;</span>
+                    <span>
+                        &lt;style&gt;CSS&lt;/style&gt;
+                        <br>
+                        &lt;script&gt;JS&lt;/script&gt;
+                    </span>
                     <hr class="main_hr">
                 '''
                 plus = ''
@@ -91,7 +95,8 @@ def main_func_setting_head(num, skin_name = ''):
                         ''' + start + '''
                         <textarea rows="25" placeholder="''' + load_lang('enter_html') + '''" name="content" id="content">''' + html.escape(data) + '''</textarea>
                         <hr class="main_hr">
-                        <button id="save" type="submit">''' + load_lang('save') + '''</button>
+                        ''' + (load_lang('main_css_warning') + '<hr class="main_hr">' if title == '_head' else '') + '''
+                        <button id="opennamu_js_save" type="submit">''' + load_lang('save') + '''</button>
                         ''' + plus + '''
                     </form>
                 ''',

+ 48 - 21
route/main_func_setting_main.py

@@ -14,13 +14,13 @@ def main_func_setting_main(db_set):
             5 : ['skin', ''],
             7 : ['reg', ''],
             8 : ['ip_view', ''],
-            9 : ['back_up', '0'],
+            9 : ['back_up', ''],
             10 : ['port', '3000'],
             11 : ['key', load_random_key()],
             12 : ['update', 'stable'],
             15 : ['encode', 'sha3'],
             16 : ['host', '0.0.0.0'],
-            19 : ['slow_edit', '0'],
+            19 : ['slow_edit', ''],
             20 : ['requires_approval', ''],
             21 : ['backup_where', ''],
             22 : ['domain', flask.request.host],
@@ -30,7 +30,11 @@ def main_func_setting_main(db_set):
             26 : ['edit_bottom_compulsion', ''],
             27 : ['http_select', 'http'],
             28 : ['title_max_length', ''],
-            29 : ['title_topic_max_length', '']
+            29 : ['title_topic_max_length', ''],
+            30 : ['password_min_length', ''],
+            31 : ['wiki_access_password_need', ''],
+            32 : ['wiki_access_password', ''],
+            33 : ['history_recording_off', '']
         }
 
         if flask.request.method == 'POST':
@@ -57,8 +61,12 @@ def main_func_setting_main(db_set):
             else:
                 conn.commit()
 
+            init_set_list = get_init_set_list()
+                
+            # 언어도 변경 가능하도록 필요
+                
             encode_select = ''
-            encode_select_data = ['sha256', 'sha3']
+            encode_select_data = init_set_list['encode']['list'] + ['sha256']
             for encode_select_one in encode_select_data:
                 if encode_select_one == d_list[15]:
                     encode_select = '<option value="' + encode_select_one + '">' + encode_select_one + '</option>' + encode_select
@@ -73,7 +81,7 @@ def main_func_setting_main(db_set):
                 else:
                     tls_select += '<option value="' + tls_select_one + '">' + tls_select_one + '</option>'
 
-            check_box_div = ['', '', '', '', '', '', '', '']
+            check_box_div = ['', '', '', '', '', '', '', '', '', '']
             for i in range(0, len(check_box_div)):
                 if i == 0:
                     acl_num = 7
@@ -89,6 +97,10 @@ def main_func_setting_main(db_set):
                     acl_num = 25
                 elif i == 7:
                     acl_num = 26
+                elif i == 8:
+                    acl_num = 31
+                elif i == 9:
+                    acl_num = 33
 
                 if d_list[acl_num]:
                     check_box_div[i] = 'checked="checked"'
@@ -106,7 +118,7 @@ def main_func_setting_main(db_set):
             return easy_minify(flask.render_template(skin_check(),
                 imp = [load_lang('main_setting'), wiki_set(), wiki_custom(), wiki_css([0, 0])],
                 data = '''
-                    <form method="post" id="main_set_data">
+                    <form method="post" id="opennamu_simple_render">
                         <h2>1. ''' + load_lang('basic_set') + '''</h2>
                         <span>''' + load_lang('wiki_name') + '''</span>
                         <hr class="main_hr">
@@ -149,6 +161,13 @@ def main_func_setting_main(db_set):
                         <span>''' + load_lang('encryption_method') + '''</span>
                         <hr class="main_hr">
                         <select name="encode">''' + encode_select + '''</select>
+                        <hr class="main_hr">
+                        
+                        <input type="checkbox" name="wiki_access_password_need" ''' + check_box_div[8] + '''> ''' + load_lang('set_wiki_access_password_need') + ''' (''' + load_lang('restart_required') + ''') (''' + load_lang('beta') + ''')
+                        <hr class="main_hr">
+                        <span>''' + load_lang('set_wiki_access_password') + ''' (''' + load_lang('restart_required') + ''') (''' + load_lang('beta') + ''')</span>
+                        <hr class="main_hr">
+                        <input type="password" name="wiki_access_password" value="''' + html.escape(d_list[32]) + '''">
 
                         <h3>1.1. ''' + load_lang('communication_set') + '''</h3>
                         <input type="checkbox" name="enable_comment" ''' + check_box_div[5] + '''> ''' + load_lang('enable_comment_function') + ''' (''' + load_lang('not_working') + ''')
@@ -160,7 +179,7 @@ def main_func_setting_main(db_set):
                         <h2>2. ''' + load_lang('design_set') + '''</h2>
                         <span>''' + load_lang('wiki_skin') + '''</span>
                         <hr class="main_hr">
-                        <select name="skin">''' + load_skin(d_list[5] if d_list[5] != '' else 'tenshi') + '''</select>
+                        <select name="skin">''' + load_skin(d_list[5] if d_list[5] != '' else 'ringo') + '''</select>
 
                         <h2>3. ''' + load_lang('login_set') + '''</h2>
                         <input type="checkbox" name="reg" ''' + check_box_div[0] + '''> ''' + load_lang('no_register') + '''
@@ -173,12 +192,13 @@ def main_func_setting_main(db_set):
                         <hr class="main_hr">
 
                         <input type="checkbox" name="ua_get" ''' + check_box_div[4] + '''> ''' + load_lang('ua_get_off') + '''
-
-                        <h2>4. ''' + load_lang('server_set') + '''</h2>
-                        <span>''' + load_lang('max_file_size') + ''' (MB)</span>
                         <hr class="main_hr">
-                        <input name="upload" value="''' + html.escape(d_list[4]) + '''">
+                        
+                        <span>''' + load_lang('password_min_length') + ''' (''' + load_lang('beta') + ''') (''' + load_lang('off') + ''' : ''' + load_lang('empty') + ''')</span>
                         <hr class="main_hr">
+                        <input name="password_min_length" value="''' + html.escape(d_list[30]) + '''">
+                        
+                        <h2>4. ''' + load_lang('server_set') + '''</h2>
 
                         <span>''' + load_lang('update_branch') + '''</span>
                         <hr class="main_hr">
@@ -187,15 +207,15 @@ def main_func_setting_main(db_set):
                         <span ''' + sqlite_only + '''>
                             <h3>4.1. ''' + load_lang('sqlite_only') + '''</h3>
                             <span>
-                                ''' + load_lang('backup_interval') + ' (' + load_lang('hour') + ') (' + load_lang('off') + ' : 0) ' + \
-                                '(' + load_lang('restart_required') + ''')</span>
+                                ''' + load_lang('backup_interval') + ''' (''' + load_lang('hour') + ''') (''' + load_lang('off') + ''' : ''' + load_lang('empty') + ''') ''' + \
+                                '''(''' + load_lang('restart_required') + ''')</span>
                             <hr class="main_hr">
                             <input name="back_up" value="''' + html.escape(d_list[9]) + '''">
                             <hr class="main_hr">
 
                             <span>
-                                ''' + load_lang('backup_where') + ' (' + load_lang('empty') + ' : ' + load_lang('default') + ') ' + \
-                                '(' + load_lang('restart_required') + ''') (''' + load_lang('example') + ''' : ./data/backup.db)
+                                ''' + load_lang('backup_where') + ''' (''' + load_lang('default') + ''' : ''' + load_lang('empty') + ''') ''' + \
+                                '''(''' + load_lang('restart_required') + ''') (''' + load_lang('example') + ''' : ./data/backup.db)
                             </span>
                             <hr class="main_hr">
                             <input name="backup_where" value="''' + html.escape(d_list[21]) + '''">
@@ -206,7 +226,7 @@ def main_func_setting_main(db_set):
                         <span><a href="/setting/acl">(''' + load_lang('main_acl_setting') + ''')</a></span>
                         <hr class="main_hr">
 
-                        <span>''' + load_lang('slow_edit') + ' (' + load_lang('second') + ') (' + load_lang('off') + ''' : 0)</span>
+                        <span>''' + load_lang('slow_edit') + ''' (''' + load_lang('second') + ''') (''' + load_lang('off') + ''' : ''' + load_lang('empty') + ''')</span>
                         <hr class="main_hr">
                         <input name="slow_edit" value="''' + html.escape(d_list[19]) + '''">
                         <hr class="main_hr">
@@ -214,20 +234,27 @@ def main_func_setting_main(db_set):
                         <input type="checkbox" name="edit_bottom_compulsion" ''' + check_box_div[7] + '''> ''' + load_lang('edit_bottom_compulsion') + ''' (''' + load_lang('beta') + ''')
                         <hr class="main_hr">
                         
-                        <span>''' + load_lang('title_max_length') + ''' (''' + load_lang('beta') + ''')</span>
+                        <span>''' + load_lang('title_max_length') + ''' (''' + load_lang('beta') + ''') (''' + load_lang('off') + ''' : ''' + load_lang('empty') + ''')</span>
                         <hr class="main_hr">
                         <input name="title_max_length" value="''' + html.escape(d_list[28]) + '''">
                         <hr class="main_hr">
                         
-                        <span>''' + load_lang('title_topic_max_length') + ''' (''' + load_lang('not_working') + ''')</span>
+                        <span>''' + load_lang('title_topic_max_length') + ''' (''' + load_lang('beta') + ''') (''' + load_lang('off') + ''' : ''' + load_lang('empty') + ''')</span>
                         <hr class="main_hr">
                         <input name="title_topic_max_length" value="''' + html.escape(d_list[29]) + '''">
                         <hr class="main_hr">
-
+                        
+                        <span>''' + load_lang('max_file_size') + ''' (MB)</span>
                         <hr class="main_hr">
-                        <button id="save" type="submit">''' + load_lang('save') + '''</button>
+                        <input name="upload" value="''' + html.escape(d_list[4]) + '''">
+                        <hr class="main_hr">
+                        
+                        <input type="checkbox" name="history_recording_off" ''' + check_box_div[9] + '''> ''' + load_lang('set_history_recording_off') + ''' (''' + load_lang('beta') + ''')
+                        <hr class="main_hr">
+
+                        <button id="opennamu_js_save" type="submit">''' + load_lang('save') + '''</button>
                     </form>
-                    <script>simple_render('main_set_data');</script>
+                    <!-- JS : opennamu_do_render_simple -->
                 ''',
                 menu = [['setting', load_lang('return')]]
             ))

+ 1 - 1
route/main_func_setting_main_logo.py

@@ -53,7 +53,7 @@ def main_func_setting_main_logo():
                 data = '''
                     <form method="post">
                         ''' + end_data + '''
-                        <button id="save" type="submit">''' + load_lang('save') + '''</button>
+                        <button id="opennamu_js_save" type="submit">''' + load_lang('save') + '''</button>
                     </form>
                 ''',
                 menu = [['setting/main', load_lang('return')]]

+ 20 - 5
route/main_func_setting_phrase.py

@@ -25,7 +25,10 @@ def main_func_setting_phrase():
             'upload_help',
             'upload_default',
             'license',
-            'topic_text'
+            'topic_text',
+            'phrase_user_page_admin',
+            'phrase_user_page_owner',
+            'phrase_old_page_warring'
         ]
         if flask.request.method == 'POST':
             for i in i_list:
@@ -57,7 +60,7 @@ def main_func_setting_phrase():
             return easy_minify(flask.render_template(skin_check(),
                 imp = [load_lang('text_setting'), wiki_set(), wiki_custom(), wiki_css([0, 0])],
                 data = '''
-                    <form method="post" id="main_set_data">
+                    <form method="post" id="opennamu_simple_render">
                         <h2>1. ''' + load_lang('register_text') + ''' (HTML)</h2>
                         <textarea rows="3" name="''' + i_list[0] + '''">''' + html.escape(d_list[0]) + '''</textarea>
 
@@ -113,14 +116,26 @@ def main_func_setting_phrase():
 
                         <h2>18. ''' + load_lang('topic_text') + '''</h2>
                         <textarea rows="3" name="''' + i_list[17] + '''">''' + html.escape(d_list[17]) + '''</textarea>
+                        
+                        <h2>19. ''' + load_lang('phrase_user_page_admin') + ''' (HTML)</h2>
+                        <textarea rows="3" name="''' + i_list[18] + '''">''' + html.escape(d_list[18]) + '''</textarea>
+                        
+                        <h2>20. ''' + load_lang('phrase_user_page_owner') + ''' (HTML)</h2>
+                        <textarea rows="3" name="''' + i_list[19] + '''">''' + html.escape(d_list[19]) + '''</textarea>
+
+                        <h2>21. ''' + load_lang('phrase_old_page_warring') + ''' (''' + load_lang('beta') + ''') (HTML)</h2>
+                        <textarea rows="3" name="''' + i_list[20] + '''">''' + html.escape(d_list[20]) + '''</textarea>
 
                         <hr class="main_hr">
-                        <button id="save" type="submit">''' + load_lang('save') + '''</button>
+                        <button id="opennamu_js_save" type="submit">''' + load_lang('save') + '''</button>
                     </form>
                     <ul id="footnote_data">
-                        <li><a href="#note_1" id="note_1_end">(1)</a> ''' + load_lang('approval_question_visible_only_when_approval_on') + '''</li>
+                        <li>
+                            <a href="#note_1" id="note_1_end">(1)</a>
+                            <a href="/setting/main">''' + load_lang('approval_question_visible_only_when_approval_on') + '''</a>
+                        </li>
                     </ul>
-                    <script>simple_render('main_set_data');</script>
+                    <!-- JS : opennamu_do_render_simple -->
                 ''',
                 menu = [['setting', load_lang('return')]]
             ))

+ 23 - 35
route/main_func_setting_robot.py

@@ -6,52 +6,38 @@ def main_func_setting_robot():
 
         if admin_check() != 1:
             return re_error('/ban')
+
+        curs.execute(db_change("select data from other where name = 'robot'"))
+        db_data = curs.fetchall()
+        if db_data:
+            data = db_data[0][0]
+        else:
+            data = ''
+
+        curs.execute(db_change("select data from other where name = 'robot_default'"))
+        db_data_2 = curs.fetchall()
+        if db_data_2 and db_data_2[0][0] != '':
+            default_data = 'checked'
+        else:
+            default_data = ''
         
         if flask.request.method == 'POST':
-            curs.execute(db_change("select name from other where name = 'robot'"))
-            if curs.fetchall():
+            if db_data:
                 curs.execute(db_change("update other set data = ? where name = 'robot'"), [flask.request.form.get('content', '')])
             else:
                 curs.execute(db_change("insert into other (name, data) values ('robot', ?)"), [flask.request.form.get('content', '')])
 
-            conn.commit()
+            if db_data_2:
+                curs.execute(db_change("update other set data = ? where name = 'robot_default'"), [flask.request.form.get('default', '')])
+            else:
+                curs.execute(db_change("insert into other (name, data) values ('robot_default', ?)"), [flask.request.form.get('default', '')])
 
-            fw = open('./robots.txt', 'w', encoding='utf8')
-            fw.write(re.sub('\r\n', '\n', flask.request.form.get('content', '')))
-            fw.close()
+            conn.commit()
 
             admin_check(None, 'edit_set (robot)')
 
             return redirect('/setting/robot')
         else:
-            if not os.path.exists('robots.txt'):
-                curs.execute(db_change('select data from other where name = "robot"'))
-                robot_test = curs.fetchall()
-                if robot_test:
-                    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', encoding='utf8')
-                    fw_test.write('User-agent: *\nDisallow: /\nAllow: /$\nAllow: /w/')
-                    fw_test.close()
-
-                    curs.execute(db_change('insert into other (name, data) values ("robot", "User-agent: *\nDisallow: /\nAllow: /$\nAllow: /w/")'))
-
-            curs.execute(db_change("select data from other where name = 'robot'"))
-            robot = curs.fetchall()
-            if robot:
-                data = robot[0][0]
-            else:
-                data = ''
-
-            f = open('./robots.txt', encoding='utf8')
-            lines = f.readlines()
-            f.close()
-
-            if not data or data == '':
-                data = ''.join(lines)
-
             return easy_minify(flask.render_template(skin_check(),
                 imp = ['robots.txt', wiki_set(), wiki_custom(), wiki_css([0, 0])],
                 data = '''
@@ -60,7 +46,9 @@ def main_func_setting_robot():
                     <form method="post">
                         <textarea rows="25" name="content">''' + html.escape(data) + '''</textarea>
                         <hr class="main_hr">
-                        <button id="save" type="submit">''' + load_lang('save') + '''</button>
+                        <input type="checkbox" name="default" ''' + default_data + '''> ''' + load_lang('default') + '''
+                        <hr class="main_hr">
+                        <button id="opennamu_js_save" type="submit">''' + load_lang('save') + '''</button>
                     </form>
                 ''',
                 menu = [['setting', load_lang('return')]]

+ 116 - 0
route/main_func_setting_sitemap.py

@@ -0,0 +1,116 @@
+from .tool.func import *
+
+def main_func_setting_sitemap():
+    with get_db_connect() as conn:
+        curs = conn.cursor()
+
+        if admin_check() != 1:
+            return re_error('/ban')
+        
+        if flask.request.method == 'POST':
+            admin_check(None, 'make sitemap')
+
+            data = '' + \
+                '<?xml version="1.0" encoding="UTF-8"?>\n' + \
+                '<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">\n' + \
+            ''
+
+            if flask.request.form.get('exclude_domain', None):
+                domain = ''
+            else:
+                domain = load_domain('full')
+
+            sql_add = ''
+            if flask.request.form.get('exclude_user_page', None):
+                sql_add += ' title not like "user:%"'
+
+            if flask.request.form.get('exclude_file_page', None):
+                if sql_add != '':
+                    sql_add += ' and'
+
+                sql_add += ' title not like "file:%"'
+
+            if flask.request.form.get('exclude_category_page', None):
+                if sql_add != '':
+                    sql_add += ' and'
+
+                sql_add += ' title not like "category:%"'
+
+            if sql_add != '':
+                sql_add = ' where' + sql_add
+
+            print(sql_add)
+            curs.execute(db_change("select title from data" + sql_add))
+            all_data = curs.fetchall()
+
+            len_all_data = len(all_data)
+            count = int(len_all_data / 30000)
+            other_count = len_all_data % 30000
+
+            for i in range(count + 1):
+                data += '<sitemap><loc>' + domain + '/sitemap_' + str(i) + '.xml</loc></sitemap>\n'
+
+            data += '' + \
+                '</sitemapindex>' + \
+            ''
+
+            f = open("sitemap.xml", 'w')
+            f.write(data)
+            f.close()
+
+            for i in range(count + 1):
+                data = '' + \
+                    '<?xml version="1.0" encoding="UTF-8"?>\n' + \
+                    '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">\n' + \
+                ''
+
+                if count == i:
+                    for x in all_data[30000 * i:]:
+                        data += '<url><loc>' + domain + '/w/' + url_pas(x[0]) + '</loc></url>\n'
+                else:
+                    for x in all_data[30000 * i:30000 * (i + 1)]:
+                        data += '<url><loc>' + domain + '/w/' + url_pas(x[0]) + '</loc></url>\n'
+
+                data += '' + \
+                    '</urlset>' + \
+                ''
+
+                f = open("sitemap_" + str(i) + ".xml", 'w')
+                f.write(data)
+                f.close()
+
+            return redirect('/setting/sitemap')
+        else:
+            sitemap_list = ''
+            if os.path.exists('sitemap.xml'):
+                sitemap_list += '<a href="/sitemap.xml">(' + load_lang('view') + ')</a>'
+
+                for_a = 0
+                while os.path.exists('sitemap_' + str(for_a) + '.xml'):
+                    sitemap_list += ' <a href="/sitemap_' + str(for_a) + '.xml">(sitemap_' + str(for_a) + '.xml)</a>'
+
+                    for_a += 1
+
+            return easy_minify(flask.render_template(skin_check(),
+                imp = [load_lang('sitemap_management'), wiki_set(), wiki_custom(), wiki_css(['(' + load_lang('beta') + ')', 0])],
+                data = '''
+                    ''' + sitemap_list + '''
+                    <hr class="main_hr">
+                    <form method="post">
+                        <input type="checkbox" name="exclude_domain"> ''' + load_lang('stiemap_exclude_domain') + '''
+                        <hr class="main_hr">
+
+                        <input type="checkbox" name="exclude_user_page"> ''' + load_lang('stiemap_exclude_user_page') + '''
+                        <hr class="main_hr">
+
+                        <input type="checkbox" name="exclude_file_page"> ''' + load_lang('stiemap_exclude_file_page') + '''
+                        <hr class="main_hr">
+
+                        <input type="checkbox" name="exclude_category_page"> ''' + load_lang('stiemap_exclude_category_page') + '''
+                        <hr class="main_hr">
+
+                        <button id="opennamu_js_save" type="submit">''' + load_lang('create') + '''</button>
+                    </form>
+                ''',
+                menu = [['setting', load_lang('return')]]
+            ))

+ 2 - 1
route/main_search.py

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

+ 27 - 31
route/main_search_deep.py

@@ -1,24 +1,35 @@
 from .tool.func import *
 
-def main_search_deep(name = 'Test'):
+def main_search_deep(name = 'Test', search_type = 'title', num = 1):
     with get_db_connect() as conn:
         curs = conn.cursor()
 
         if name == '':
             return redirect()
 
-        num = int(number_check(flask.request.args.get('num', '1')))
         sql_num = (num * 50 - 50) if num * 50 > 0 else 0
 
-        div = '<ul class="inside_ul">'
+        div = ''
+        if search_type == 'title':
+            div += '<a href="/search_data/1/' + url_pas(name) + '">(' + load_lang('search_document_data') + ')</a>'
+        else:
+            div += '<a href="/search/1/' + url_pas(name) + '">(' + load_lang('search_document_name') + ')</a>'
+
+        name_new = ''
+        if re.search(r'^분류:', name):
+            name_new = re.sub(r"^분류:", 'category:', name)
+        elif re.search(r"^사용자:", name):
+            name_new = re.sub(r"^사용자:", 'user:', name)
+        elif re.search(r"^파일:", name):
+            name_new = re.sub(r"^파일:", 'file:', name)
 
-        div_plus = ''
-        test = ''
+        if name_new != '':
+            div += ' <a href="/search/1/' + url_pas(name_new) + '">(' + name_new + ')</a>'
 
         curs.execute(db_change("select title from data where title = ?"), [name])
         link_id = '' if curs.fetchall() else 'id="not_thing"'
 
-        div = '''
+        div += '''
             <ul class="inside_ul">
                 <li>
                     <a ''' + link_id + ' href="/w/' + url_pas(name) + '">' + html.escape(name) + '''</a>
@@ -28,36 +39,21 @@ def main_search_deep(name = 'Test'):
             <ul class="inside_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("" + \
-                "select distinct title, case " + \
-                "when title like ? then 'title' else 'data' end from data " + \
-                "where (title like ? or data like ?) order by case " + \
-                "when title like ? then 1 else 2 end limit ?, 50"),
-                ['%' + name + '%', '%' + name + '%', '%' + name + '%', '%' + name + '%', sql_num]
+        if search_type == 'title':
+            curs.execute(db_change("select title from data where title like ? order by title limit ?, 50"),
+                ['%' + name + '%', sql_num]
             )
-            all_list = curs.fetchall()
-            if all_list:
-                test = all_list[0][1]
-
-                for data in all_list:
-                    if data[1] != test:
-                        div_plus += '</ul><hr class="main_hr"><ul class="inside_ul">'
-
-                        test = data[1]
-
-                    div_plus += '<li><a href="/w/' + url_pas(data[0]) + '">' + html.escape(data[0]) + '</a> (' + data[1] + ')</li>'
         else:
-            curs.execute(db_change("select title from data where title like ? order by title limit ?, 50"),
+            curs.execute(db_change("select title from data where data like ? order by title limit ?, 50"),
                 ['%' + name + '%', sql_num]
             )
-            all_list = curs.fetchall()
-            for data in all_list:
-                div_plus += '<li><a href="/w/' + url_pas(data[0]) + '">' + data[0] + '</a> (title)</li>'
 
-        div += div_plus + '</ul>'
-        div += next_fix('/search/' + url_pas(name) + '?num=', num, all_list)
+        all_list = curs.fetchall()
+        for data in all_list:
+            div += '<li><a href="/w/' + url_pas(data[0]) + '">' + data[0] + '</a></li>'
+
+        div += '</ul>'
+        div += get_next_page_bottom('/search/{}/' + url_pas(name), num, all_list)
 
         return easy_minify(flask.render_template(skin_check(),
             imp = [name, wiki_set(), wiki_custom(), wiki_css(['(' + load_lang('search') + ')', 0])],

+ 26 - 25
route/main_sys_restart.py

@@ -1,31 +1,32 @@
 from .tool.func import *
 
 def main_sys_restart():
-    if admin_check() != 1:
-        return re_error('/error/3')
+    with get_db_connect() as conn:
+        if admin_check() != 1:
+            return re_error('/error/3')
 
-    if flask.request.method == 'POST':
-        admin_check(None, 'restart')
+        if flask.request.method == 'POST':
+            admin_check(None, 'restart')
 
-        print('----')
-        print('Restart')
+            print('----')
+            print('Restart')
 
-        try:
-            os.execl(sys.executable, sys.executable, *sys.argv)
-        except:
-            pass
-        
-        try:
-            os.execl(sys.executable, '"' + sys.executable + '"', *sys.argv)
-        except:
-            return re_error('/error/33')
-    else:
-        return easy_minify(flask.render_template(skin_check(),
-            imp = [load_lang('wiki_restart'), wiki_set(), wiki_custom(), wiki_css([0, 0])],
-            data = '''
-                <form method="post">
-                    <button type="submit">''' + load_lang('restart') + '''</button>
-                </form>
-            ''',
-            menu = [['manager', load_lang('return')]]
-        ))
+            try:
+                os.execl(sys.executable, sys.executable, *sys.argv)
+            except:
+                pass
+
+            try:
+                os.execl(sys.executable, '"' + sys.executable + '"', *sys.argv)
+            except:
+                return re_error('/error/33')
+        else:
+            return easy_minify(flask.render_template(skin_check(),
+                imp = [load_lang('wiki_restart'), wiki_set(), wiki_custom(), wiki_css([0, 0])],
+                data = '''
+                    <form method="post">
+                        <button type="submit">''' + load_lang('restart') + '''</button>
+                    </form>
+                ''',
+                menu = [['manager', load_lang('return')]]
+            ))

+ 20 - 17
route/main_sys_shutdown.py

@@ -1,23 +1,26 @@
 from .tool.func import *
 
 def main_sys_shutdown():
-    if admin_check() != 1:
-        return re_error('/error/3')
+    with get_db_connect() as conn:
+        if admin_check() != 1:
+            return re_error('/error/3')
 
-    if flask.request.method == 'POST':
-        admin_check(None, 'shutdown')
+        if flask.request.method == 'POST':
+            admin_check(None, 'shutdown')
 
-        print('----')
-        print('shutdown')
+            conn.commit()
 
-        os._exit(os.EX_OK)
-    else:
-        return easy_minify(flask.render_template(skin_check(),
-            imp = [load_lang('wiki_shutdown'), wiki_set(), wiki_custom(), wiki_css([0, 0])],
-            data = '''
-                <form method="post">
-                    <button type="submit">''' + load_lang('shutdown') + '''</button>
-                </form>
-            ''',
-            menu = [['manager', load_lang('return')]]
-        ))
+            print('----')
+            print('Shutdown')
+
+            os._exit(os.EX_OK)
+        else:
+            return easy_minify(flask.render_template(skin_check(),
+                imp = [load_lang('wiki_shutdown'), wiki_set(), wiki_custom(), wiki_css([0, 0])],
+                data = '''
+                    <form method="post">
+                        <button type="submit">''' + load_lang('shutdown') + '''</button>
+                    </form>
+                ''',
+                menu = [['manager', load_lang('return')]]
+            ))

+ 5 - 5
route/main_sys_update.py

@@ -46,17 +46,17 @@ def main_sys_update():
             return easy_minify(flask.render_template(skin_check(),
                 imp = [load_lang('update'), wiki_set(), wiki_custom(), wiki_css([0, 0])],
                 data = load_lang('update_warning') + '''
-                    <hr class=\"main_hr\">
+                    <hr class="main_hr">
                     <ul class="inside_ul">
-                        <li>''' + load_lang('version') + ''' : <span id="ver_send_2"></span></li>
-                        <li id="ver_send" style="display: none;">''' + load_lang('lastest') + ''' : </li>
+                        <li id="ver_send_2">''' + load_lang('version') + ''' : </li>
+                        <li id="ver_send">''' + load_lang('lastest') + ''' : </li>
                     </ul>
                     <a href="https://github.com/openNAMU/openNAMU">(Beta)</a> <a href="https://github.com/openNAMU/openNAMU/tree/stable">(Stable)</a>
-                    <hr class=\"main_hr\">
+                    <hr class="main_hr">
                     <form method="post">
                         <button type="submit">''' + load_lang('update') + '''</button>
                     </form>
-                    <script>load_ver();</script>
+                    <!-- JS : opennamu_do_insert_version -->
                 ''',
                 menu = [['manager', load_lang('return')]]
             ))

+ 13 - 65
route/main_tool_admin.py

@@ -1,44 +1,25 @@
 from .tool.func import *
 
-def main_tool_admin(num = 1, add_2 = ''):
-    title_list = {
-        0 : [load_lang('document_name'), 'acl', load_lang('acl')],
-        1 : [0, 'check', load_lang('check')],
-        2 : [load_lang('file_name'), 'file_filter/add', load_lang('file_filter_add')],
-        3 : [0, 'admin', load_lang('authorize')],
-        4 : [0, 'record', load_lang('edit_record')],
-        5 : [0, 'record/topic', load_lang('discussion_record')],
-        6 : [load_lang('name'), 'admin_plus', load_lang('add_admin_group')],
-        7 : [load_lang('name'), 'edit_filter/add', load_lang('edit_filter_add')],
-        8 : [load_lang('document_name'), 'search', load_lang('search')],
-        9 : [0, 'block_log/user', load_lang('blocked_user')],
-        10 : [0, 'block_log/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('load')],
-        14 : [load_lang('document_name'), 'star_doc', load_lang('add_star_doc')],
-        15 : [load_lang('name_or_ip_or_regex'), 'ban', load_lang('release')]
-    }
-
-    if num == 1:
+def main_tool_admin():
+    with get_db_connect() as conn:
         return easy_minify(flask.render_template(skin_check(),
             imp = [load_lang('admin_tool'), wiki_set(), wiki_custom(), wiki_css([0, 0])],
             data = '''
-                <div id="other_simple_render">
+                <div id="opennamu_simple_render">
                     <h2>1. ''' + load_lang('admin') + '''</h2>
                     <ul class="inside_ul">
                         <li><a href="/manager/2">''' + load_lang('acl_change') + '''</a></li>
                         <li><a href="/manager/3">''' + load_lang('check_user') + '''</a></li>
-                        <li><a href="/ban">''' + load_lang('ban') + '''</a></li>
+                        <li><a href="/auth/give/ban">''' + load_lang('ban') + '''</a></li>
+                        <li><a href="/auth/give/ban_multiple">''' + load_lang('multiple_ban') + '''</a></li>
                         <li><a href="/manager/17">''' + load_lang('release') + '''</a></li>
                         <li><a href="/manager/5">''' + load_lang('authorize') + '''</a></li>
                     </ul>
                     <h2>2. ''' + load_lang('owner') + '''</h2>
                     <ul class="inside_ul">
                         <li><a href="/admin_group">''' + load_lang('admin_group_list') + '''</a></li>
-                        <li><a href="/delete_mutiple">''' + load_lang('many_delete') + '''</a></li>
+                        <li><a href="/delete_multiple">''' + load_lang('many_delete') + '''</a></li>
                         <li><a href="/app_submit">''' + load_lang('application_list') + '''</a></li>
-                        <li><a href="/api/sitemap.xml">''' + load_lang('get_sitemap') + '''</a></li>
                         <li><a href="/register">''' + load_lang('add_user') + '''</a></li>
                         <li><a href="/setting">''' + load_lang('setting') + '''</a></li>
                     </ul>
@@ -52,7 +33,7 @@ def main_tool_admin(num = 1, add_2 = ''):
                         <li><a href="/name_filter">''' + load_lang('id_filter_list') + '''</a></li>
                         <li><a href="/file_filter">''' + load_lang('file_filter_list') + '''</a></li>
                         <li><a href="/extension_filter">''' + load_lang('extension_filter_list') + '''</a></li>
-                        <li><a href="/filter/document/list">''' + load_lang('document_filter_list') + '''</a></li>
+                        <li><a href="/filter/document/list">''' + load_lang('document_filter_list') + ''' (''' + load_lang('beta') + ''')</a></li>
                     </ul>
                     <h3>2.2. ''' + load_lang('server') + '''</h2>
                     <ul class="inside_ul">
@@ -62,8 +43,8 @@ def main_tool_admin(num = 1, add_2 = ''):
                     </ul>
                     <h2>3. ''' + load_lang('version') + '''</h2>
                     <ul class="inside_ul">
-                        <li>''' + load_lang('version') + ''' : <span id="ver_send_2"></span></li>
-                        <li id="ver_send" style="display: none;">''' + load_lang('lastest') + ''' : </li>
+                        <li id="ver_send_2">''' + load_lang('version') + ''' : </li>
+                        <li id="ver_send">''' + load_lang('lastest') + ''' : </li>
                     </ul>
                     <h3>3.1. ''' + load_lang('skin_info') + '''</h3>
                     <ul class="inside_ul">
@@ -71,42 +52,9 @@ def main_tool_admin(num = 1, add_2 = ''):
                         <div id="ver_send_3"></div>
                     </ul>
                 </div>
-                <script>load_ver(); do_skin_ver_check(); simple_render('other_simple_render');</script>
+                <!-- JS : opennamu_do_insert_version -->
+                <!-- JS : opennamu_do_insert_version_skin -->
+                <!-- JS : opennamu_do_render_simple -->
             ''',
             menu = [['other', load_lang('return')]]
-        ))
-    elif not num - 1 > len(title_list):
-        num -= 2
-        
-        add_1 = flask.request.form.get('name', 'test')
-        if flask.request.method == 'POST':
-            if add_2 != '':
-                return redirect('/' + title_list[num][1] + '/' + url_pas(add_2) + '/doc_from/' + url_pas(add_1))
-            elif flask.request.form.get('regex', '') != '':
-                return redirect('/' + title_list[num][1] + '/' + url_pas(add_1) + '?type=regex')
-            else:
-                return redirect('/' + title_list[num][1] + '/' + url_pas(add_1))
-        else:
-            if title_list[num][0] == 0:
-                placeholder = load_lang('user_name')
-            else:
-                placeholder = title_list[num][0]
-
-            plus = ''
-            if num == 15:
-                plus = '<input type="checkbox" name="regex"> ' + load_lang('regex') + '<hr class="main_hr">'
-
-            return easy_minify(flask.render_template(skin_check(),
-                imp = [title_list[num][2], wiki_set(), wiki_custom(), wiki_css([0, 0])],
-                data = '''
-                    <form method="post">
-                        <input placeholder="''' + placeholder + '''" name="name" type="text">
-                        <hr class="main_hr">
-                        ''' + plus + '''
-                        <button type="submit">''' + load_lang('go') + '''</button>
-                    </form>
-                ''',
-                menu = [['manager', load_lang('return')]]
-            ))
-    else:
-        return redirect()
+        ))

+ 0 - 0
route/main_tool_guide.py


+ 54 - 53
route/main_tool_other.py

@@ -1,56 +1,57 @@
 from .tool.func import *
 
 def main_tool_other():
-    return easy_minify(flask.render_template(skin_check(),
-        imp = [load_lang('other_tool'), wiki_set(), wiki_custom(), wiki_css([0, 0])],
-        data = '''
-            <div id="other_simple_render">
-                <h2>1. ''' + load_lang('record') + '''</h2>
-                <ul class="inside_ul">
-                    <li><a href="/manager/6">''' + load_lang('edit_record') + '''</a></li>
-                    <li><a href="/manager/7">''' + load_lang('discussion_record') + '''</a></li>
-                </ul>
-                <h2>2. ''' + load_lang('list') + '''</h2>
-                <h3>2.1. ''' + load_lang('admin') + '''</h3>
-                <ul class="inside_ul">               
-                    <li><a href="/admin_list">''' + load_lang('admin_list') + '''</a></li>
-                    <li><a href="/admin_log">''' + load_lang('authority_use_list') + '''</a></li>
-                </ul>
-                <h3>2.2. ''' + load_lang('discussion') + '''</h3>
-                <ul class="inside_ul">
-                    <li><a href="/recent_discuss">''' + load_lang('recent_discussion') + '''</a></li>
-                </ul>
-                <h3>2.3. ''' + load_lang('document') + '''</h3>
-                <ul class="inside_ul">
-                    <li><a href="/recent_changes">''' + load_lang('recent_change') + '''</a></li>
-                    <li><a href="/title_index">''' + load_lang('all_document_list') + '''</a></li>
-                    <li><a href="/acl_list">''' + load_lang('acl_document_list') + '''</a></li>
-                    <li><a href="/please">''' + load_lang('need_document') + '''</a></li>
-                    <li><a href="/long_page">''' + load_lang('long_page') + '''</a></li>
-                    <li><a href="/short_page">''' + load_lang('short_page') + '''</a></li>
-                    <li><a href="/old_page">''' + load_lang('old_page') + '''</a></li>
-                </ul>
-                <h3>2.4. ''' + load_lang('user') + '''</h3>
-                <ul class="inside_ul">
-                    <li><a href="/block_log">''' + load_lang('recent_ban') + '''</a></li>
-                    <li><a href="/user_log">''' + load_lang('member_list') + '''</a></li>
-                </ul>
-                <h3>2.5. ''' + load_lang('other') + '''</h3>
-                <ul class="inside_ul">
-                    <li><a href="/image_file_list">''' + load_lang('image_file_list') + '''</a></li>
-                    <li><a href="/vote">''' + load_lang('vote_list') + '''</a></li>
-                </ul>
-                <h2>3. ''' + load_lang('other') + '''</h2>
-                <ul class="inside_ul">
-                    <li><a href="/upload">''' + load_lang('upload') + '''</a></li>
-                    <li><a href="/manager/10">''' + load_lang('search') + '''</a></li>
-                </ul>
-                <h2>4. ''' + load_lang('admin') + '''</h2>
-                <ul class="inside_ul">
-                    <li><a href="/manager/1">''' + load_lang('admin_tool') + '''</a></li>
-                </ul>
-            </div>
-            <script>simple_render('other_simple_render');</script>
-        ''',
-        menu = 0
-    ))
+    with get_db_connect() as conn:
+        return easy_minify(flask.render_template(skin_check(),
+            imp = [load_lang('other_tool'), wiki_set(), wiki_custom(), wiki_css([0, 0])],
+            data = '''
+                <div id="opennamu_simple_render">
+                    <h2>1. ''' + load_lang('record') + '''</h2>
+                    <ul class="inside_ul">
+                        <li><a href="/manager/6">''' + load_lang('edit_record') + '''</a></li>
+                        <li><a href="/manager/7">''' + load_lang('discussion_record') + '''</a></li>
+                    </ul>
+                    <h2>2. ''' + load_lang('list') + '''</h2>
+                    <h3>2.1. ''' + load_lang('admin') + '''</h3>
+                    <ul class="inside_ul">               
+                        <li><a href="/admin_list">''' + load_lang('admin_list') + '''</a></li>
+                        <li><a href="/admin_log">''' + load_lang('authority_use_list') + '''</a></li>
+                    </ul>
+                    <h3>2.2. ''' + load_lang('discussion') + '''</h3>
+                    <ul class="inside_ul">
+                        <li><a href="/recent_discuss">''' + load_lang('recent_discussion') + '''</a></li>
+                    </ul>
+                    <h3>2.3. ''' + load_lang('document') + '''</h3>
+                    <ul class="inside_ul">
+                        <li><a href="/recent_changes">''' + load_lang('recent_change') + '''</a></li>
+                        <li><a href="/title_index">''' + load_lang('all_document_list') + '''</a></li>
+                        <li><a href="/acl_list">''' + load_lang('acl_document_list') + '''</a></li>
+                        <li><a href="/please">''' + load_lang('need_document') + '''</a></li>
+                        <li><a href="/long_page">''' + load_lang('long_page') + '''</a></li>
+                        <li><a href="/short_page">''' + load_lang('short_page') + '''</a></li>
+                        <li><a href="/old_page">''' + load_lang('old_page') + '''</a></li>
+                    </ul>
+                    <h3>2.4. ''' + load_lang('user') + '''</h3>
+                    <ul class="inside_ul">
+                        <li><a href="/block_log">''' + load_lang('recent_ban') + '''</a></li>
+                        <li><a href="/user_log">''' + load_lang('member_list') + '''</a></li>
+                    </ul>
+                    <h3>2.5. ''' + load_lang('other') + '''</h3>
+                    <ul class="inside_ul">
+                        <li><a href="/image_file_list">''' + load_lang('image_file_list') + '''</a></li>
+                        <li><a href="/vote">''' + load_lang('vote_list') + '''</a></li>
+                    </ul>
+                    <h2>3. ''' + load_lang('other') + '''</h2>
+                    <ul class="inside_ul">
+                        <li><a href="/upload">''' + load_lang('upload') + '''</a></li>
+                        <li><a href="/manager/10">''' + load_lang('search') + '''</a></li>
+                    </ul>
+                    <h2>4. ''' + load_lang('admin') + '''</h2>
+                    <ul class="inside_ul">
+                        <li><a href="/manager/1">''' + load_lang('admin_tool') + '''</a></li>
+                    </ul>
+                </div>
+                <!-- JS : opennamu_do_render_simple -->
+            ''',
+            menu = 0
+        ))

+ 61 - 0
route/main_tool_redirect.py

@@ -0,0 +1,61 @@
+from .tool.func import *
+
+def main_tool_redirect(num = 1, add_2 = ''):
+    with get_db_connect() as conn:
+        title_list = {
+            0 : [load_lang('document_name'), 'acl', load_lang('acl')],
+            1 : [0, 'check', load_lang('check')],
+            2 : [load_lang('file_name'), 'file_filter/add', load_lang('file_filter_add')],
+            3 : [0, 'admin', load_lang('authorize')],
+            4 : [0, 'record', load_lang('edit_record')],
+            5 : [0, 'record/topic', load_lang('discussion_record')],
+            6 : [load_lang('name'), 'admin_plus', load_lang('add_admin_group')],
+            7 : [load_lang('name'), 'edit_filter/add', load_lang('edit_filter_add')],
+            8 : [load_lang('document_name'), 'search', load_lang('search')],
+            9 : [0, 'block_log/user', load_lang('blocked_user')],
+            10 : [0, 'block_log/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('load')],
+            14 : [load_lang('document_name'), 'star_doc', load_lang('add_star_doc')],
+            15 : [load_lang('name_or_ip_or_regex'), 'auth/give/ban', load_lang('release')]
+        }
+        
+        if num == 1:
+            return redirect('/manager')
+        elif not num - 1 > len(title_list):
+            num -= 2
+
+            add_1 = flask.request.form.get('name', 'test')
+            if flask.request.method == 'POST':
+                if add_2 != '':
+                    flask.session['edit_load_document'] = add_1
+                    return redirect('/edit_from/' + url_pas(add_2))
+                elif flask.request.form.get('regex', '') != '':
+                    return redirect('/auth/give/ban_regex/' + url_pas(add_1))
+                else:
+                    return redirect('/' + title_list[num][1] + '/' + url_pas(add_1))
+            else:
+                if title_list[num][0] == 0:
+                    placeholder = load_lang('user_name')
+                else:
+                    placeholder = title_list[num][0]
+
+                plus = ''
+                if num == 15:
+                    plus = '<input type="checkbox" name="regex"> ' + load_lang('regex') + '<hr class="main_hr">'
+
+                return easy_minify(flask.render_template(skin_check(),
+                    imp = [title_list[num][2], wiki_set(), wiki_custom(), wiki_css([0, 0])],
+                    data = '''
+                        <form method="post">
+                            <input placeholder="''' + placeholder + '''" name="name" type="text">
+                            <hr class="main_hr">
+                            ''' + plus + '''
+                            <button type="submit">''' + load_lang('go') + '''</button>
+                        </form>
+                    ''',
+                    menu = [['manager', load_lang('return')]]
+                ))
+        else:
+            return redirect()

+ 24 - 23
route/main_view.py

@@ -2,29 +2,30 @@ from .tool.func import *
 from .main_error_404 import main_error_404
 
 def main_view(name = ''):
-    file_name = re.search(r'([^/]+)$', name)
-    if not file_name:
-        return main_error_404(conn)
-    else:
-        file_name = file_name.group(1)
-        dir_name = './views/' + re.sub(r'\.{2,}', '', re.sub(r'([^/]+)$', '', name))
-
-        mime_type = file_name.split('.')
-        if len(mime_type) < 2:
-            mime_type = 'text/plain'
+    with get_db_connect() as conn:
+        file_name = re.search(r'([^/]+)$', name)
+        if not file_name:
+            return main_error_404()
         else:
-            mime_type = mime_type[len(mime_type) - 1].lower()
-            image_type = ['jpeg', 'jpg', 'gif', 'png', 'webp']
-            if mime_type in image_type:
-                mime_type = 'image/' + mime_type
-            elif mime_type == 'js':
-                mime_type = 'text/javascript'
-            elif mime_type == 'txt':
+            file_name = file_name.group(1)
+            dir_name = './views/' + re.sub(r'\.{2,}', '', re.sub(r'([^/]+)$', '', name))
+
+            mime_type = file_name.split('.')
+            if len(mime_type) < 2:
                 mime_type = 'text/plain'
             else:
-                mime_type = 'text/' + mime_type
-        
-        return flask.send_from_directory(
-            dir_name, file_name, 
-            mimetype = mime_type
-        )
+                mime_type = mime_type[len(mime_type) - 1].lower()
+                image_type = ['jpeg', 'jpg', 'gif', 'png', 'webp', 'ico']
+                if mime_type in image_type:
+                    mime_type = 'image/' + mime_type
+                elif mime_type == 'js':
+                    mime_type = 'text/javascript'
+                elif mime_type == 'txt':
+                    mime_type = 'text/plain'
+                else:
+                    mime_type = 'text/' + mime_type
+
+            return flask.send_from_directory(
+                dir_name, file_name, 
+                mimetype = mime_type
+            )

+ 21 - 8
route/main_view_file.py

@@ -2,12 +2,25 @@ from .tool.func import *
 from .main_error_404 import main_error_404
 
 def main_view_file(data = ''):
-    if data == 'robots.txt' and not os.path.exists('robots.txt'):
-        return flask.Response('User-agent: *\nDisallow: /\nAllow: /$\nAllow: /w/', mimetype = 'text/plain')
-    elif os.path.exists(data):
-        if re.search(r'\.txt$', data, flags = re.I):
-            return flask.send_from_directory('./', data, mimetype = 'text/plain')
-        else:
-            return flask.send_from_directory('./', data, mimetype = 'text/xml')
+    with get_db_connect() as conn:
+        if data == 'robots.txt':
+            curs = conn.cursor()
 
-    return main_error_404()
+            curs.execute(db_change("select data from other where name = 'robot_default'"))
+            db_data = curs.fetchall()
+            if db_data and db_data[0][0] != '':
+                return flask.Response(get_default_robots_txt(), mimetype = 'text/plain')
+            else:
+                curs.execute(db_change("select data from other where name = 'robot'"))
+                db_data = curs.fetchall()
+                if db_data:
+                    return flask.Response(db_data[0][0], mimetype = 'text/plain')
+                else:
+                    return flask.Response(get_default_robots_txt(), mimetype = 'text/plain')
+        elif os.path.exists(data):
+            if re.search(r'\.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()

+ 13 - 12
route/main_view_image.py

@@ -2,15 +2,16 @@ from .tool.func import *
 from .main_error_404 import main_error_404
 
 def main_view_image(name = ''):
-    mime_type = re.search(r'([^.]+)$', name)
-    if mime_type:
-        mime_type = mime_type.group(1).lower()
-        if mime_type == 'svg':
-            mime_type = 'svg+xml'
-        
-        return flask.send_from_directory(
-            './' + load_image_url(), name, 
-            mimetype = 'image/' + mime_type
-        )
-    else:
-        return main_error_404()
+    with get_db_connect() as conn:
+        mime_type = re.search(r'([^.]+)$', name)
+        if mime_type:
+            mime_type = mime_type.group(1).lower()
+            if mime_type == 'svg':
+                mime_type = 'svg+xml'
+
+            return flask.send_from_directory(
+                './' + load_image_url(), name, 
+                mimetype = 'image/' + mime_type
+            )
+        else:
+            return main_error_404()

+ 138 - 137
route/recent_app_submit.py

@@ -1,145 +1,146 @@
 from .tool.func import *
 
-def recent_app_submit_2(conn):
-    curs = conn.cursor()
-
-    div = ''
-
-    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 += load_lang('approval_requirement_disabled')
-
-    if flask.request.method == 'GET':
-        curs.execute(db_change(
-            'select data from user_set where name = "application"'
-        ))
-        db_data = curs.fetchall()
-        if db_data:
-            div += '' + \
-                load_lang('all_register_num') + ' : ' + str(len(db_data)) + \
-                '<hr class="main_hr">' + \
-            ''
-            
-            div += '''
-                <table id="main_table_set">
-                    <tr id="main_table_top_tr">
-                        <td id="main_table_width_half">''' + load_lang('id') + '''</td>
-                        <td id="main_table_width_half">''' + load_lang('email') + '''</td>
-                    </tr>
-                    <tr id="main_table_top_tr">
-                        <td>''' + load_lang('approval_question') + '''</td>
-                        <td>''' + load_lang('answer') + '''</td>
-                    </tr>                        
-            '''
-
-            for application in db_data:
-                application = json.loads(application[0])
-                
-                if 'question' in application:
-                    question = html.escape(application['question'])
-                    question = question if question != '' else '<br>'
-                else:
-                    question = '<br>'
-                    
-                if 'answer' in application:
-                    answer = html.escape(application['answer'])
-                    answer = answer if answer != '' else '<br>'
-                else:
-                    answer = '<br>'
-                    
-                    
-                if 'email' in application:
-                    email = html.escape(application['email'])
-                    email = email if email != '' else '<br>'
-                else:
-                    email = '<br>'
-                
+def recent_app_submit_2():
+    with get_db_connect() as conn:
+        curs = conn.cursor()
+
+        div = ''
+
+        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 += load_lang('approval_requirement_disabled')
+
+        if flask.request.method == 'GET':
+            curs.execute(db_change(
+                'select data from user_set where name = "application"'
+            ))
+            db_data = curs.fetchall()
+            if db_data:
+                div += '' + \
+                    load_lang('all_register_num') + ' : ' + str(len(db_data)) + \
+                    '<hr class="main_hr">' + \
+                ''
+
                 div += '''
-                    <form method="post">
-                        <tr>
-                            <td>''' + application['id'] + '''</td>
-                            <td>''' + email + '''</td>
+                    <table id="main_table_set">
+                        <tr id="main_table_top_tr">
+                            <td id="main_table_width_half">''' + load_lang('id') + '''</td>
+                            <td id="main_table_width_half">''' + load_lang('email') + '''</td>
                         </tr>
-                        <tr>
-                            <td>''' + question + '''</td>
-                            <td>''' + answer + '''</td>
-                        </tr>
-                        <tr>
-                            <td colspan="3">
-                                <button type="submit" 
-                                        id="save"
-                                        name="approve" 
-                                        value="''' + application['id'] + '''">
-                                    ''' + load_lang('approve') + '''
-                                </button>
-                                <button type="submit" 
-                                        name="decline" 
-                                        value="''' + application['id'] + '''">
-                                    ''' + load_lang('decline') + '''
-                                </button>
-                            </td>
-                        </tr>
-                    </form>
+                        <tr id="main_table_top_tr">
+                            <td>''' + load_lang('approval_question') + '''</td>
+                            <td>''' + load_lang('answer') + '''</td>
+                        </tr>                        
                 '''
-                
-            div += '</table>'
-        else:
-            div += load_lang('no_applications_now')
-
-        return easy_minify(flask.render_template(skin_check(),
-            imp = [load_lang('application_list'), wiki_set(), wiki_custom(), wiki_css([0, 0])],
-            data = div,
-            menu = [['other', load_lang('return')]]
-        ))
-    else:
-        if admin_check(None, 'app submit') != 1:
-            return re_error('/ban')
-        
-        if flask.request.form.get('approve', '') != '':
-            curs.execute(db_change(
-                'select data from user_set where id = ? and name = "application"'
-            ), [
-                flask.request.form.get('approve', '')
-            ])
-            application = curs.fetchall()
-            if not application:
-                return re_error('/error/26')
+
+                for application in db_data:
+                    application = json.loads(application[0])
+
+                    if 'question' in application:
+                        question = html.escape(application['question'])
+                        question = question if question != '' else '<br>'
+                    else:
+                        question = '<br>'
+
+                    if 'answer' in application:
+                        answer = html.escape(application['answer'])
+                        answer = answer if answer != '' else '<br>'
+                    else:
+                        answer = '<br>'
+
+
+                    if 'email' in application:
+                        email = html.escape(application['email'])
+                        email = email if email != '' else '<br>'
+                    else:
+                        email = '<br>'
+
+                    div += '''
+                        <form method="post">
+                            <tr>
+                                <td>''' + application['id'] + '''</td>
+                                <td>''' + email + '''</td>
+                            </tr>
+                            <tr>
+                                <td>''' + question + '''</td>
+                                <td>''' + answer + '''</td>
+                            </tr>
+                            <tr>
+                                <td colspan="3">
+                                    <button type="submit" 
+                                            id="opennamu_js_save"
+                                            name="approve" 
+                                            value="''' + application['id'] + '''">
+                                        ''' + load_lang('approve') + '''
+                                    </button>
+                                    <button type="submit" 
+                                            name="decline" 
+                                            value="''' + application['id'] + '''">
+                                        ''' + load_lang('decline') + '''
+                                    </button>
+                                </td>
+                            </tr>
+                        </form>
+                    '''
+
+                div += '</table>'
             else:
-                application = json.loads(application[0][0])
-            
-            add_user(
-                application['id'], 
-                application['pw'],
-                application['email'],
-                application['encode']
-            )
+                div += load_lang('no_applications_now')
 
-            curs.execute(db_change(
-                "insert into user_set (name, id, data) values ('approval_question', ?, ?)"
-            ), [
-                application['id'], 
-                application['question']
-            ])
-            curs.execute(db_change(
-                "insert into user_set (name, id, data) values ('approval_question_answer', ?, ?)"
-            ), [
-                application['id'], 
-                application['answer']
-            ])
-            
-            curs.execute(db_change(
-                'delete from user_set where id = ? and name = "application"'
-            ), [
-                application['id']
-            ])
-            conn.commit()
-        elif flask.request.form.get('decline', '') != '':
-            curs.execute(db_change(
-                'delete from user_set where id = ? and name = "application"'
-            ), [
-                flask.request.form.get('decline', '')
-            ])
-            conn.commit()
+            return easy_minify(flask.render_template(skin_check(),
+                imp = [load_lang('application_list'), wiki_set(), wiki_custom(), wiki_css([0, 0])],
+                data = div,
+                menu = [['other', load_lang('return')]]
+            ))
+        else:
+            if admin_check(None, 'app submit') != 1:
+                return re_error('/ban')
+
+            if flask.request.form.get('approve', '') != '':
+                curs.execute(db_change(
+                    'select data from user_set where id = ? and name = "application"'
+                ), [
+                    flask.request.form.get('approve', '')
+                ])
+                application = curs.fetchall()
+                if not application:
+                    return re_error('/error/26')
+                else:
+                    application = json.loads(application[0][0])
+
+                add_user(
+                    application['id'], 
+                    application['pw'],
+                    application['email'],
+                    application['encode']
+                )
+
+                curs.execute(db_change(
+                    "insert into user_set (name, id, data) values ('approval_question', ?, ?)"
+                ), [
+                    application['id'], 
+                    application['question']
+                ])
+                curs.execute(db_change(
+                    "insert into user_set (name, id, data) values ('approval_question_answer', ?, ?)"
+                ), [
+                    application['id'], 
+                    application['answer']
+                ])
+
+                curs.execute(db_change(
+                    'delete from user_set where id = ? and name = "application"'
+                ), [
+                    application['id']
+                ])
+                conn.commit()
+            elif flask.request.form.get('decline', '') != '':
+                curs.execute(db_change(
+                    'delete from user_set where id = ? and name = "application"'
+                ), [
+                    flask.request.form.get('decline', '')
+                ])
+                conn.commit()
 
-        return redirect('/app_submit')
+            return redirect('/app_submit')

+ 130 - 129
route/recent_block.py

@@ -1,150 +1,151 @@
 from .tool.func import *
 
-def recent_block_2(conn, name, tool):
-    curs = conn.cursor()
-
-    num = int(number_check(flask.request.args.get('num', '1')))
-    sql_num = (num * 50 - 50) if num * 50 > 0 else 0
-
-    div = '''
-        <table id="main_table_set">
-            <tbody>
-                <tr id="main_table_top_tr">
-                    <td id="main_table_width">''' + load_lang('blocked') + '''</td>
-                    <td id="main_table_width">''' + load_lang('admin') + '''</td>
-                    <td id="main_table_width">''' + load_lang('period') + '''</td>
-                </tr>
-    '''
-
-    curs.execute(db_change("update rb set ongoing = '' where end < ? and end != '' and ongoing = '1'"), [get_time()])
-    conn.commit()
+def recent_block_2(name, tool):
+    with get_db_connect() as conn:
+        curs = conn.cursor()
+
+        num = int(number_check(flask.request.args.get('num', '1')))
+        sql_num = (num * 50 - 50) if num * 50 > 0 else 0
+
+        div = '''
+            <table id="main_table_set">
+                <tbody>
+                    <tr id="main_table_top_tr">
+                        <td id="main_table_width">''' + load_lang('blocked') + '''</td>
+                        <td id="main_table_width">''' + load_lang('admin') + '''</td>
+                        <td id="main_table_width">''' + load_lang('period') + '''</td>
+                    </tr>
+        '''
 
-    get_type = flask.request.args.get('type', '')
-    sub_type = flask.request.args.get('s_type', '')
-    if tool == 'all':
-        if get_type == 'ongoing':
-            sub = ' (' + load_lang('in_progress') + ')'
+        curs.execute(db_change("update rb set ongoing = '' where end < ? and end != '' and ongoing = '1'"), [get_time()])
+        conn.commit()
+
+        get_type = flask.request.args.get('type', '')
+        sub_type = flask.request.args.get('s_type', '')
+        if tool == 'all':
+            if get_type == 'ongoing':
+                sub = ' (' + load_lang('in_progress') + ')'
+
+                if sub_type == '':
+                    div = '' + \
+                        '<a href="?type=ongoing&s_type=regex">(' + load_lang('regex') + ')</a> ' + \
+                        '<a href="?type=ongoing&s_type=normal">(' + load_lang('normal') + ')</a>' + \
+                        '<hr class="main_hr">' + \
+                    '' + div
+                    menu = [['block_log', load_lang('return')]]
+                    plus_sql = ''
+                else:
+                    menu = [['block_log?type=ongoing', load_lang('return')]]
+
+                    if sub_type == 'regex':
+                        sub += ' (' + load_lang('regex') + ')'
+                        plus_sql = 'and band = \'regex\' '
+                    else:
+                        sub += ' (' + load_lang('normal') + ')'
+                        plus_sql = 'and band = \'\' '
+
+                curs.execute(db_change("" + \
+                    "select why, block, blocker, end, today, band, ongoing from rb " + \
+                    "where ((end > ? and end like '2%') or end = '') and ongoing = '1' " + plus_sql + \
+                    "order by end desc limit ?, 50" + \
+                ""), [
+                    get_time(),
+                    sql_num
+                ])
+            else:
+                sub = 0
+                menu = 0
 
-            if sub_type == '':
                 div = '' + \
-                    '<a href="?type=ongoing&s_type=regex">(' + load_lang('regex') + ')</a> ' + \
-                    '<a href="?type=ongoing&s_type=normal">(' + load_lang('normal') + ')</a>' + \
+                    '<a href="/manager/11">(' + load_lang('blocked') + ')</a> ' + \
+                    '<a href="/manager/12">(' + load_lang('admin') + ')</a> ' + \
+                    '<a href="?type=ongoing">(' + load_lang('in_progress') + ')</a>' + \
                     '<hr class="main_hr">' + \
                 '' + div
-                menu = [['block_log', load_lang('return')]]
-                plus_sql = ''
-            else:
-                menu = [['block_log?type=ongoing', load_lang('return')]]
-                
-                if sub_type == 'regex':
-                    sub += ' (' + load_lang('regex') + ')'
-                    plus_sql = 'and band = \'regex\' '
-                else:
-                    sub += ' (' + load_lang('normal') + ')'
-                    plus_sql = 'and band = \'\' '
+
+                curs.execute(db_change("" + \
+                    "select why, block, blocker, end, today, band, ongoing " + \
+                    "from rb order by today desc limit ?, 50" + \
+                ""), [sql_num])
+        elif tool == 'user':
+            sub = ' (' + load_lang('blocked') + ')'
+            menu = [['block_log', load_lang('normal')]]
 
             curs.execute(db_change("" + \
-                "select why, block, blocker, end, today, band, ongoing from rb " + \
-                "where ((end > ? and end like '2%') or end = '') and ongoing = '1' " + plus_sql + \
-                "order by end desc limit ?, 50" + \
+                "select why, block, blocker, end, today, band, ongoing " + \
+                "from rb where block = ? order by today desc limit ?, 50" + \
             ""), [
-                get_time(),
+                name, 
                 sql_num
             ])
         else:
-            sub = 0
-            menu = 0
-
-            div = '' + \
-                '<a href="/manager/11">(' + load_lang('blocked') + ')</a> ' + \
-                '<a href="/manager/12">(' + load_lang('admin') + ')</a> ' + \
-                '<a href="?type=ongoing">(' + load_lang('in_progress') + ')</a>' + \
-                '<hr class="main_hr">' + \
-            '' + div
+            sub = ' (' + load_lang('admin') + ')'
+            menu = [['block_log', load_lang('normal')]]
 
             curs.execute(db_change("" + \
                 "select why, block, blocker, end, today, band, ongoing " + \
-                "from rb order by today desc limit ?, 50" + \
-            ""), [sql_num])
-    elif tool == 'user':
-        sub = ' (' + load_lang('blocked') + ')'
-        menu = [['block_log', load_lang('normal')]]
-
-        curs.execute(db_change("" + \
-            "select why, block, blocker, end, today, band, ongoing " + \
-            "from rb where block = ? order by today desc limit ?, 50" + \
-        ""), [
-            name, 
-            sql_num
-        ])
-    else:
-        sub = ' (' + load_lang('admin') + ')'
-        menu = [['block_log', load_lang('normal')]]
-
-        curs.execute(db_change("" + \
-            "select why, block, blocker, end, today, band, ongoing " + \
-            "from rb where blocker = ? order by today desc limit ?, 50" + \
-        ""), [
-            name, 
-            sql_num
-        ])
-
-    data_list = curs.fetchall()
-    all_ip = ip_pas([i[1] for i in data_list] + [i[2] for i in data_list])
-    for data in data_list:
-        why = '<br>' if data[0] == '' else html.escape(data[0])
-
-        if data[5] == 'regex':
-            ip = data[1]
-            if data[6] == '1':
-                ip = '<s>' + ip + '</s> <a href="/ban/' + url_pas(data[1]) + '?type=regex">(' + load_lang('release') + ')</a>'
+                "from rb where blocker = ? order by today desc limit ?, 50" + \
+            ""), [
+                name, 
+                sql_num
+            ])
+
+        data_list = curs.fetchall()
+        all_ip = ip_pas([i[1] for i in data_list] + [i[2] for i in data_list])
+        for data in data_list:
+            why = '<br>' if data[0] == '' else html.escape(data[0])
+
+            if data[5] == 'regex':
+                ip = data[1]
+                if data[6] == '1':
+                    ip = '<s>' + ip + '</s> <a href="/auth/give/ban_regex/' + url_pas(data[1]) + '">(' + load_lang('release') + ')</a>'
+                else:
+                    ip += ' <a href="/auth/give/ban_regex/' + url_pas(data[1]) + '">(' + load_lang('ban') + ')</a>'
+
+                ip += ' (' + load_lang('regex') + ')'
             else:
-                ip += ' <a href="/ban/' + url_pas(data[1]) + '?type=regex">(' + load_lang('ban') + ')</a>'
-                
-            ip += ' (' + load_lang('regex') + ')'
-        else:
-            ip = all_ip[data[1]]
+                ip = all_ip[data[1]]
 
-        if data[3] == '':
-            end = load_lang('limitless')
-        elif data[3] == 'release':
-            end = load_lang('release')
-        else:
-            end = data[3]
+            if data[3] == '':
+                end = load_lang('limitless')
+            elif data[3] == 'release':
+                end = load_lang('release')
+            else:
+                end = data[3]
 
-        if data[2] == '':
-            admin = ''
-        elif re.search(r'^tool:', data[2]):
-            admin = data[2]
+            if data[2] == '':
+                admin = ''
+            elif re.search(r'^tool:', data[2]):
+                admin = data[2]
+            else:
+                admin = all_ip[data[2]]
+
+            start = load_lang('start') + ' : ' + (data[4] if data[4] != '' else '0')
+            div += '''
+                <tr>
+                    <td>''' + ip + '''</td>
+                    <td>''' + admin + '''</td>
+                    <td>
+                        ''' + start + '''
+                        <br>
+                        ''' + load_lang('end') + ' : ' + end + '''
+                    </td>
+                </tr>
+                <tr>
+                    <td colspan="3">''' + why + '''</td>
+                </tr>
+            '''
+
+        div += '</tbody>'
+        div += '</table>'
+
+        if tool == 'all':
+            div += next_fix('/block_log?num=', num, data_list)
         else:
-            admin = all_ip[data[2]]
-
-        start = load_lang('start') + ' : ' + (data[4] if data[4] != '' else '0')
-        div += '''
-            <tr>
-                <td>''' + ip + '''</td>
-                <td>''' + admin + '''</td>
-                <td>
-                    ''' + start + '''
-                    <br>
-                    ''' + load_lang('end') + ' : ' + end + '''
-                </td>
-            </tr>
-            <tr>
-                <td colspan="3">''' + why + '''</td>
-            </tr>
-        '''
+            div += next_fix('/block_log/' + url_pas(tool) + '/' + url_pas(name) + '?num=', num, data_list)
 
-    div += '</tbody>'
-    div += '</table>'
-    
-    if tool == 'all':
-        div += next_fix('/block_log?num=', num, data_list)
-    else:
-        div += next_fix('/block_log/' + url_pas(tool) + '/' + url_pas(name) + '?num=', num, data_list)
-
-    return easy_minify(flask.render_template(skin_check(),
-        imp = [load_lang('recent_ban'), wiki_set(), wiki_custom(), wiki_css([sub, 0])],
-        data = div,
-        menu = menu
-    ))
+        return easy_minify(flask.render_template(skin_check(),
+            imp = [load_lang('recent_ban'), wiki_set(), wiki_custom(), wiki_css([sub, 0])],
+            data = div,
+            menu = menu
+        ))

+ 19 - 7
route/recent_change.py

@@ -1,5 +1,20 @@
 from .tool.func import *
 
+def recent_change_send_render(data):
+    def send_render_href_replace(match):
+        match = match.group(1)
+        data_unescape = html.unescape(match)
+
+        return '<a href="/w/' + url_pas(data_unescape) + '">' + match + '</a>'
+
+    if data == '&lt;br&gt;' or data == '':
+        data = '<br>'
+    else:
+        data = data.replace('javascript:', '')
+        data = re.sub(r'&lt;a(?:(?:(?!&gt;).)*)&gt;((?:(?!&lt;\/a&gt;).)+)&lt;\/a&gt;', send_render_href_replace, data)
+
+    return data
+
 def recent_change(name = None, tool = ''):
     with get_db_connect() as conn:
         curs = conn.cursor()
@@ -105,8 +120,8 @@ def recent_change(name = None, tool = ''):
 
                 if data[6] == 'O':
                     if admin == 1:
-                        style[0] = 'id="toron_color_grey"'
-                        style[1] = 'id="toron_color_grey"'
+                        style[0] = 'class="opennamu_history_blind"'
+                        style[1] = 'class="opennamu_history_blind"'
                     else:
                         ip = ''
                         ban = ''
@@ -114,7 +129,7 @@ def recent_change(name = None, tool = ''):
                         send = ''
 
                         style[0] = 'style="display: none;"'
-                        style[1] = 'id="toron_color_grey"'
+                        style[1] = 'class="opennamu_history_blind"'
 
                 if tool == 'history':
                     title = '<a href="/w_rev/' + data[0] + '/' + url_pas(name) + '">r' + data[0] + '</a> '
@@ -132,16 +147,13 @@ def recent_change(name = None, tool = ''):
                         <td>''' + date + '''</td>
                     </tr>
                     <tr ''' + style[1] + '''>
-                        <td class="send_content" colspan="3">
-                            ''' + (html.escape(send) if send != '' else '<br>') + '''
-                        </td>
+                        <td colspan="3">''' + recent_change_send_render(html.escape(send)) + '''</td>
                     </tr>
                 '''
 
             div += '''
                     </tbody>
                 </table>
-                <script>send_render();</script>
             '''
 
             if name:

+ 17 - 6
route/recent_history_add.py

@@ -30,23 +30,34 @@ def recent_history_add(name = 'Test'):
 
             return redirect('/history/' + url_pas(name))
         else:
+            curs.execute(db_change('select data from other where name = "edit_help"'))
+            sql_d = curs.fetchall()
+            p_text = html.escape(sql_d[0][0]) if sql_d and sql_d[0][0] != '' else load_lang('default_edit_help')
+            
             return easy_minify(flask.render_template(skin_check(),
                 imp = [load_lang('history_add'), wiki_set(), wiki_custom(), wiki_css(['(' + name + ')', 0])],
                 data = '''
                     <form method="post">
-                        <script>do_stop_exit();</script>
-                        ''' + edit_button() + '''
-                        <textarea rows="25" id="content" name="content"></textarea>
+                        <textarea style="display: none;" id="opennamu_js_edit_origin"></textarea>
+                        <textarea style="display: none;" id="opennamu_js_edit_textarea" name="content"></textarea>
+                        
+                        <div>''' + edit_button() + '''</div>
+                        
+                        <textarea id="opennamu_js_edit_textarea_view" class="content" placeholder="''' + p_text + '''"></textarea>
                         <hr class="main_hr">
+                        
                         <input placeholder="''' + load_lang('why') + '''" name="send" type="text">
                         <hr class="main_hr">
+                        
                         <input placeholder="''' + load_lang('name') + '''" name="get_ip" type="text">
                         <hr class="main_hr">
-                        <button id="save" type="submit" onclick="go_save_zone = 1;">''' + load_lang('save') + '''</button>
-                        <button id="preview" type="button" onclick="load_preview(\'''' + url_pas(name) + '\')">' + load_lang('preview') + '''</button>
+                        
+                        <button id="opennamu_js_save" type="submit">''' + load_lang('save') + '''</button>
+                        <button id="opennamu_js_preview" type="button">''' + load_lang('preview') + '''</button>
                     </form>
+                    
                     <hr class="main_hr">
-                    <div id="see_preview"></div>
+                    <div id="opennamu_js_preview_area"></div>
                 ''',
                 menu = [['history/' + url_pas(name), load_lang('return')]]
             ))

+ 2 - 2
route/recent_history_tool.py

@@ -23,7 +23,7 @@ def recent_history_tool(name = 'Test', rev = 1):
         data += '</ul>'
 
         if admin_check(6) == 1:
-            data += '<h3>admin</h3>'
+            data += '<h3>' + load_lang('admin') + '</h3>'
             data += '<ul class="inside_ul">'
             curs.execute(db_change('' + \
                 'select title from history ' + \
@@ -39,7 +39,7 @@ def recent_history_tool(name = 'Test', rev = 1):
             data += '</ul>'
 
         if admin_check() == 1:
-            data += '<h3>owner</h3>'
+            data += '<h3>' + load_lang('owner') + '</h3>'
             data += '<ul class="inside_ul">'
             data += '<li><a href="/history_delete/' + num + '/' + url_pas(name) + '">' + load_lang('history_delete') + '</li>'
             data += '<li><a href="/history_send/' + num + '/' + url_pas(name) + '">' + load_lang('send_edit') + '</li>'

+ 343 - 168
route/tool/func.py

@@ -130,55 +130,12 @@ def get_init_set_list(need = 'all'):
             'display' : 'Encryption method',
             'require' : 'select',
             'default' : 'sha3',
-            'list' : ['sha3', 'sha3-512']
+            'list' : ['sha3', 'sha3-salt', 'sha3-512', 'sha3-512-salt']
         }
     }
     
     return init_set_list
 
-class get_db_connect_old:
-    def __init__(self, db_set):
-        self.db_set = db_set
-        self.conn = ''
-        
-    def db_load(self):
-        if self.db_set['type'] == 'sqlite':
-            self.conn = sqlite3.connect(
-                self.db_set['name'] + '.db',
-                check_same_thread = False,
-                isolation_level = None
-            )
-            self.conn.execute('pragma journal_mode = wal')
-        else:
-            self.conn = pymysql.connect(
-                host = self.db_set['mysql_host'],
-                user = self.db_set['mysql_user'],
-                password = self.db_set['mysql_pw'],
-                charset = 'utf8mb4',
-                port = int(self.db_set['mysql_port']),
-            )
-            curs = self.conn.cursor()
-
-            try:
-                curs.execute(db_change(
-                    'create database ' + self.db_set['name'] + ' ' + \
-                    'default character set utf8mb4;'
-                ))
-            except:
-                pass
-
-            self.conn.select_db(self.db_set['name'])
-
-        load_conn(self.conn)
-
-        return self.conn
-
-    def db_get(self):
-        # if self.db_set['type'] != 'sqlite':
-        #     self.conn.ping(reconnect = True)
-            
-        return self.conn
-    
 class get_db_connect:
     # 임시 DB 커넥션 동작 구조
     # Init 파트
@@ -212,14 +169,6 @@ class get_db_connect:
             )
             curs = self.conn.cursor()
 
-            try:
-                curs.execute(db_change(
-                    'create database ' + self.db_set['name'] + ' ' + \
-                    'default character set utf8mb4;'
-                ))
-            except:
-                pass
-
             self.conn.select_db(self.db_set['name'])
 
         load_conn(self.conn)
@@ -369,6 +318,8 @@ def get_db_table_list():
     create_data['back'] = ['title', 'link', 'type']
 
     # 폐지 예정 (topic_set으로 통합) [가장 시급]
+    create_data['topic_set'] = ['thread_code', 'set_name', 'set_id', 'set_data']
+
     create_data['rd'] = ['title', 'sub', 'code', 'date', 'band', 'stop', 'agree', 'acl']
     create_data['topic'] = ['id', 'data', 'date', 'ip', 'block', 'top', 'code']
 
@@ -634,6 +585,37 @@ def update(ver_num, set_data):
         for for_a in db_table_list:
             for for_b in db_table_list[for_a]:
                 curs.execute(db_change("update " + for_a + " set " + for_b + " = '' where " + for_b + " is null"))
+                
+    if ver_num < 3500112:
+        # curs.execute(db_change('select id from user_set where name = "email" and data = ?'), [user_email])
+        curs.execute(db_change('select id from user_set where name = "email"'))
+        for db_data in curs.fetchall():
+            if ip_or_user(db_data[0]) == 1:
+                curs.execute(db_change(
+                    'delete from user_set where id = ? and name = "email"'
+                ), [db_data[0]])
+                
+    if ver_num < 3500113:
+        db_table_list = get_db_table_list()
+        for for_a in db_table_list:
+            for for_b in db_table_list[for_a]:
+                curs.execute(db_change("update " + for_a + " set " + for_b + " = '' where " + for_b + " is null"))
+
+    if ver_num < 3500114:
+        curs.execute(db_change('delete from alarm'))
+
+    if ver_num < 3500354:
+        curs.execute(db_change("select data from other where name = 'robot'"))
+        db_data = curs.fetchall()
+        if db_data:
+            robot_default = '' + \
+                'User-agent: *\n' + \
+                'Disallow: /\n' + \
+                'Allow: /$\n' + \
+                'Allow: /w/' + \
+            ''
+            if db_data[0][0] == robot_default:
+                curs.execute(db_change("insert into other (name, data) values ('robot_default', 'on')"))
 
     conn.commit()
     
@@ -642,6 +624,8 @@ def update(ver_num, set_data):
     print('Update completed')
 
 def set_init_always(ver_num):
+    global global_wiki_set
+    
     curs = conn.cursor()
 
     curs.execute(db_change('delete from other where name = "ver"'))
@@ -652,6 +636,26 @@ def set_init_always(ver_num):
 
     if not os.path.exists(load_image_url()):
         os.makedirs(load_image_url())
+
+    curs.execute(db_change('select data from other where name = "key"'))
+    if not curs.fetchall():
+        curs.execute(db_change('insert into other (name, data) values ("key", ?)'), [load_random_key()])
+        
+    curs.execute(db_change('select data from other where name = "salt_key"'))
+    if not curs.fetchall():
+        curs.execute(db_change('insert into other (name, data) values ("salt_key", ?)'), [load_random_key(4)])
+
+    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")'))
+        
+    curs.execute(db_change('select data from other where name = "wiki_access_password_need"'))
+    db_data = curs.fetchall()
+    if db_data and db_data[0][0] != '':
+        curs.execute(db_change('select data from other where name = "wiki_access_password"'))
+        db_data = curs.fetchall()
+        if db_data:
+            global_wiki_set['wiki_access_password'] = db_data[0][0]
     
     conn.commit()
     
@@ -686,15 +690,6 @@ def set_init():
             curs.execute(db_change(
                 "insert into other (name, data) values (?, ?)"
             ), [i[0], i[1]])
-            
-    curs.execute(db_change('select data from other where name = "key"'))
-    rep_data = curs.fetchall()
-    if not rep_data:
-        curs.execute(db_change('insert into other (name, data) values ("key", ?)'), [load_random_key()])
-
-    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()
 
@@ -703,6 +698,22 @@ def set_init():
 def get_default_admin_group():
     return ['owner', 'ban']
 
+def get_default_robots_txt():
+    data = '' + \
+        'User-agent: *\n' + \
+        'Disallow: /\n' + \
+        'Allow: /$\n' + \
+        'Allow: /w/' + \
+    ''
+
+    if os.path.exists('sitemap.xml'):
+        data += '' + \
+            '\n' + \
+            'Sitemap: ' + load_domain('full') + '/sitemap.xml' + \
+        ''
+
+    return data
+
 def get_user_title_list():
     # default
     user_title = {
@@ -727,9 +738,31 @@ def http_warning():
     return '''
         <div id="opennamu_http_warning_text"></div>
         <span style="display: none;" id="opennamu_http_warning_text_lang">''' + load_lang('http_warning') + '''</span>
-        <script>opennamu_do_warning_text();</script>
     '''
 
+def get_next_page_bottom(link, num, page, end = 50):
+    list_data = ''
+
+    if num == 1:
+        if len(page) == end:
+            list_data += '' + \
+                '<hr class="main_hr">' + \
+                '<a href="' + link.format(str(num + 1)) + '">(' + load_lang('next') + ')</a>' + \
+            ''
+    elif len(page) != end:
+        list_data += '' + \
+            '<hr class="main_hr">' + \
+            '<a href="' + link.format(str(num - 1)) + '">(' + load_lang('previous') + ')</a>' + \
+        ''
+    else:
+        list_data += '' + \
+            '<hr class="main_hr">' + \
+            '<a href="' + link.format(str(num - 1)) + '">(' + load_lang('previous') + ')</a> ' + \
+            '<a href="' + link.format(str(num + 1)) + '">(' + load_lang('next') + ')</a>' + \
+        ''
+
+    return list_data
+
 def next_fix(link, num, page, end = 50):
     list_data = ''
 
@@ -804,7 +837,6 @@ def load_domain(data_type = 'normal'):
         curs.execute(db_change("select data from other where name = 'domain'"))
         db_data = curs.fetchall()
         domain += db_data[0][0] if db_data and db_data[0][0] != '' else flask.request.host
-        domain += '/'
     else:
         curs.execute(db_change("select data from other where name = 'domain'"))
         db_data = curs.fetchall()
@@ -826,7 +858,7 @@ def edit_button(editor_display = '0'):
     for insert_data in insert_list:
         data += '' + \
             '<a href="' + \
-                'javascript:do_insert_data(\'textarea_edit_view\', \'' + insert_data[0] + '\', ' + editor_display + ')' + \
+                'javascript:do_insert_data(\'opennamu_js_edit_textarea_view\', \'' + insert_data[0] + '\', ' + editor_display + ')' + \
             '">(' + insert_data[1] + ')</a> ' + \
         ''
 
@@ -857,20 +889,29 @@ def ip_warning():
     return text_data
     
 # Func-login    
-def pw_encode(data, db_data = ''):
+def pw_encode(data, db_data_encode = ''):
     curs = conn.cursor()
 
-    if db_data == '':
+    if db_data_encode == '':
         curs.execute(db_change('select data from other where name = "encode"'))
         db_data = curs.fetchall()
-        db_data = db_data[0][0] if db_data else 'sha3'
+        db_data_encode = db_data[0][0] if db_data else 'sha3'
 
-    if db_data == 'sha256':
+    if db_data_encode == 'sha256':
         return hashlib.sha256(bytes(data, 'utf-8')).hexdigest()
-    elif db_data == 'sha3-512':
-        return hashlib.sha3_512(bytes(data, 'utf-8')).hexdigest()
-    else: # type_d == 'sha3'
+    elif db_data_encode == 'sha3':
         return hashlib.sha3_256(bytes(data, 'utf-8')).hexdigest()
+    elif db_data_encode == 'sha3-512':
+        return hashlib.sha3_512(bytes(data, 'utf-8')).hexdigest()
+    else:
+        curs.execute(db_change('select data from other where name = "salt_key"'))
+        db_data = curs.fetchall()
+        db_data_salt = db_data[0][0] if db_data else ''
+        
+        if db_data_encode == 'sha3-salt':
+            return hashlib.sha3_256(bytes(data + db_data_salt, 'utf-8')).hexdigest()
+        else:
+            return hashlib.sha3_512(bytes(data + db_data_salt, 'utf-8')).hexdigest()
 
 def pw_check(data, data2, type_d = 'no', id_d = ''):
     curs = conn.cursor()
@@ -902,8 +943,20 @@ def pw_check(data, data2, type_d = 'no', id_d = ''):
 # Func-skin
 def easy_minify(data, tool = None):
     # without_DB
-
-    return data
+    if 'wiki_access_password' in global_wiki_set:
+        access_password = global_wiki_set['wiki_access_password']
+        input_password = flask.request.cookies.get('opennamu_wiki_access', ' ')
+        if url_pas(access_password) == input_password:
+            return data
+            
+        return '''
+            <script src="/views/main_css/js/route/wiki_access_password.js"></script>
+            <h2>''' + load_lang('error_password_require_for_wiki_access') + '''</h2>
+            <input type="password" id="wiki_access">
+            <input type="submit" onclick="opennamu_do_wiki_access();">
+        '''
+    else:
+        return data
 
 def load_lang(data, safe = 0):
     curs = conn.cursor()
@@ -954,7 +1007,7 @@ def skin_check(set_n = 0):
     curs = conn.cursor()
 
     # 개편 필요?
-    skin_list = load_skin('tenshi', 1)
+    skin_list = load_skin('ringo', 1)
     skin = skin_list[0]
     ip = ip_check()
     
@@ -987,27 +1040,33 @@ def wiki_css(data):
     data += ['' for _ in range(0, 3 - len(data))]
     
     data_css = ''
-    data_css_ver = '147'
+    data_css_ver = '155'
     
-    # Func JS
+    # Func JS + Defer
     data_css += '<script src="/views/main_css/js/func/func.js?ver=' + data_css_ver + '"></script>'
     
-    data_css += '<script src="/views/main_css/js/func/http_warning_text.js?ver=' + data_css_ver + '"></script>'
-    data_css += '<script src="/views/main_css/js/func/ie_end_of_life.js?ver=' + data_css_ver + '"></script>'
-    data_css += '<script src="/views/main_css/js/func/shortcut.js?ver=' + data_css_ver + '"></script>'
-    data_css += '<script src="/views/main_css/js/func/user_name_parser.js?ver=' + data_css_ver + '"></script>'
+    data_css += '<script defer src="/views/main_css/js/func/insert_version.js?ver=' + data_css_ver + '"></script>'
+    data_css += '<script defer src="/views/main_css/js/func/insert_user_info.js?ver=' + data_css_ver + '"></script>'
+    data_css += '<script defer src="/views/main_css/js/func/insert_version_skin.js?ver=' + data_css_ver + '"></script>'
+    data_css += '<script defer src="/views/main_css/js/func/insert_http_warning_text.js?ver=' + data_css_ver + '"></script>'
+    
+    data_css += '<script defer src="/views/main_css/js/func/ie_end_of_life.js?ver=' + data_css_ver + '"></script>'
+    data_css += '<script defer src="/views/main_css/js/func/shortcut.js?ver=' + data_css_ver + '"></script>'
+    
+    data_css += '<script defer src="/views/main_css/js/func/render_user_name.js?ver=' + data_css_ver + '"></script>'
+    data_css += '<script defer src="/views/main_css/js/func/render_simple.js?ver=' + data_css_ver + '"></script>'
     
     # Render JS
     data_css += '<script src="/views/main_css/js/render/markdown.js?ver=' + data_css_ver + '"></script>'
     data_css += '<script src="/views/main_css/js/render/wiki.js?ver=' + data_css_ver + '"></script>'
     
-    # Route JS
-    data_css += '<script src="/views/main_css/js/route/thread.js?ver=' + data_css_ver + '"></script>'
+    # Route JS + Defer
+    data_css += '<script defer src="/views/main_css/js/route/edit.js?ver=' + data_css_ver + '"></script>'
+    data_css += '<script defer src="/views/main_css/js/route/thread.js?ver=' + data_css_ver + '"></script>'
     
     # 레거시 일반 JS
     data_css += '<script src="/views/main_css/js/load_editor.js?ver=' + data_css_ver + '"></script>'
     data_css += '<script src="/views/main_css/js/load_skin_set.js?ver=' + data_css_ver + '"></script>'
-    data_css += '<script src="/views/main_css/js/load_something.js?ver=' + data_css_ver + '"></script>'
     
     # 레거시 렌더러 JS
     data_css += '<script src="/views/main_css/js/render_html.js?ver=' + data_css_ver + '"></script>'
@@ -1022,7 +1081,7 @@ def wiki_css(data):
     data_css += '<script src="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.5.0/build/highlight.min.js"></script>'
     
     data_css += '<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.15.3/dist/katex.min.css" integrity="sha384-KiWOvVjnN8qwAZbuQyWDIbfCLFhLXNETzBQjA/92pIowpC0d2O3nppDGQVgwd2nB" crossorigin="anonymous">'
-    data_css += '<script defer src="https://cdn.jsdelivr.net/npm/katex@0.15.3/dist/katex.min.js" integrity="sha384-0fdwu/T/EQMsQlrHCCHoH10pkPLlKA1jL5dFyUOvB3lfeT2540/2g6YgSi2BL14p" crossorigin="anonymous"></script>'
+    data_css += '<script src="https://cdn.jsdelivr.net/npm/katex@0.15.3/dist/katex.min.js" integrity="sha384-0fdwu/T/EQMsQlrHCCHoH10pkPLlKA1jL5dFyUOvB3lfeT2540/2g6YgSi2BL14p" crossorigin="anonymous"></script>'
 
     data = data[0:2] + ['', data_css] + data[2:]
 
@@ -1039,50 +1098,39 @@ def cut_100(data):
 def wiki_set(num = 1):
     curs = conn.cursor()
 
-    if num == 1:
-        skin_name = skin_check(1)
-        data_list = []
+    skin_name = skin_check(1)
+    data_list = []
 
-        curs.execute(db_change('select data from other where name = ?'), ['name'])
-        db_data = curs.fetchall()
-        data_list += [db_data[0][0]] if db_data and db_data[0][0] != '' else ['Wiki']
+    curs.execute(db_change('select data from other where name = ?'), ['name'])
+    db_data = curs.fetchall()
+    data_list += [db_data[0][0]] if db_data and db_data[0][0] != '' else ['Wiki']
 
-        curs.execute(db_change('select data from other where name = "license"'))
-        db_data = curs.fetchall()
-        data_list += [db_data[0][0]] if db_data and db_data[0][0] != '' else ['ARR']
+    curs.execute(db_change('select data from other where name = "license"'))
+    db_data = curs.fetchall()
+    data_list += [db_data[0][0]] if db_data and db_data[0][0] != '' else ['ARR']
 
-        data_list += ['', '']
+    data_list += ['', '']
 
-        curs.execute(db_change('select data from other where name = "logo" and coverage = ?'), [skin_name])
+    curs.execute(db_change('select data from other where name = "logo" and coverage = ?'), [skin_name])
+    db_data = curs.fetchall()
+    if db_data and db_data[0][0] != '':
+        data_list += [db_data[0][0]]
+    else:
+        curs.execute(db_change('select data from other where name = "logo" and coverage = ""'))
         db_data = curs.fetchall()
-        if db_data and db_data[0][0] != '':
-            data_list += [db_data[0][0]]
-        else:
-            curs.execute(db_change('select data from other where name = "logo" and coverage = ""'))
-            db_data = curs.fetchall()
-            data_list += [db_data[0][0]] if db_data and db_data[0][0] != '' else [data_list[0]]
+        data_list += [db_data[0][0]] if db_data and db_data[0][0] != '' else [data_list[0]]
 
-        head_data = ''
+    head_data = ''
 
-        curs.execute(db_change("select data from other where name = 'head' and coverage = ''"))
-        db_data = curs.fetchall()
-        head_data += db_data[0][0] if db_data and db_data[0][0] != '' else ''
+    curs.execute(db_change("select data from other where name = 'head' and coverage = ''"))
+    db_data = curs.fetchall()
+    head_data += db_data[0][0] if db_data and db_data[0][0] != '' else ''
 
-        curs.execute(db_change("select data from other where name = 'head' and coverage = ?"), [skin_name])
-        db_data = curs.fetchall()
-        head_data += db_data[0][0] if db_data and db_data[0][0] != '' else ''
-            
-        data_list += [head_data]
-    elif num == 2:
-        curs.execute(db_change('select data from other where name = "frontpage"'))
-        db_data = curs.fetchall()
-        data_list = db_data[0][0] if db_data and db_data[0][0] != '' else 'FrontPage'
-    elif num == 3:
-        curs.execute(db_change('select data from other where name = "upload"'))
-        db_data = curs.fetchall()
-        data_list = db_data[0][0] if db_data and db_data[0][0] != '' else '2'
-    else:
-        data_list = ''
+    curs.execute(db_change("select data from other where name = 'head' and coverage = ?"), [skin_name])
+    db_data = curs.fetchall()
+    head_data += db_data[0][0] if db_data and db_data[0][0] != '' else ''
+
+    data_list += [head_data]
 
     return data_list
 
@@ -1090,13 +1138,29 @@ def wiki_custom():
     curs = conn.cursor()
 
     ip = ip_check()
+    skin_name = '_' + skin_check(1)
+
     if ip_or_user(ip) == 0:
         user_icon = 1
         user_name = ip
 
-        curs.execute(db_change("select data from user_set where id = ? and name = 'custom_css'"), [ip])
-        user_head = curs.fetchall()
-        user_head = user_head[0][0] if user_head else ''
+        if 'head' in flask.session:
+            user_head = flask.session['head']
+        else:
+            curs.execute(db_change("select data from user_set where id = ? and name = 'custom_css'"), [ip])
+            db_data = curs.fetchall()
+            user_head = db_data[0][0] if db_data else ''
+
+            flask.session['head'] = db_data[0][0] if db_data else ''
+
+        if 'head' + skin_name in flask.session:
+            user_head += flask.session['head' + skin_name]
+        else:
+            curs.execute(db_change("select data from user_set where id = ? and name = ?"), [ip, 'custom_css' + skin_name])
+            db_data = curs.fetchall()
+            user_head += db_data[0][0] if db_data else ''
+
+            flask.session['head' + skin_name] = db_data[0][0] if db_data else ''
         
         curs.execute(db_change('select data from user_set where name = "email" and id = ?'), [ip])
         email = curs.fetchall()
@@ -1128,6 +1192,7 @@ def wiki_custom():
         user_acl_list = '0'
         user_notice = '0'
         user_head = flask.session['head'] if 'head' in flask.session else ''
+        user_head += flask.session['head' + skin_name] if 'head' + skin_name in flask.session else ''
 
     curs.execute(db_change("select title from rd where title = ? and stop = ''"), ['user:' + ip])
     user_topic = '1' if curs.fetchall() else '0'
@@ -1213,12 +1278,38 @@ def render_set(doc_name = '', doc_data = '', data_type = 'view', data_in = '', d
     else:
         if data_type == 'raw':
             return doc_data
-        else:
-            if doc_data != 0:
-                get_class_render = class_do_render(conn)
-                return get_class_render.do_render(doc_name, doc_data, data_type, data_in)
+        
+        if doc_data != 0:
+            render_lang_data = {
+                'toc' : load_lang('toc'),
+                'category' : load_lang('category')
+            }
+
+            get_class_render = class_do_render(conn, render_lang_data).do_render(doc_name, doc_data, data_type, data_in)
+
+            if data_type == 'backlink':
+                return ''
+
+            if 'include' in get_class_render[2]:
+                for include_data in get_class_render[2]['include']:
+                    if acl_check(include_data[1], 'render') == 0:
+                        include_regex = re.compile('<div id="' + include_data[0] + '"><\/div>')
+                        
+                        include_data_render = class_do_render(conn, render_lang_data).do_render(include_data[1], include_data[2], data_type, include_data[0] + data_in)
+                        include_data_render[0] = '<div id="' + include_data[0] + '">' + include_data_render[0] + '</div>'
+
+                        get_class_render[0] = re.sub(include_regex, include_data_render[0], get_class_render[0])
+                        get_class_render[1] += include_data_render[1]
+
+            if data_type == 'api_view':
+                return [
+                    get_class_render[0], 
+                    get_class_render[1]
+                ]
             else:
-                return 'HTTP Request 404'
+                return get_class_render[0] + '<script>' + get_class_render[1] + '</script>'
+        else:
+            return 'HTTP Request 404'
 
 # Func-request
 def send_email(who, title, data):
@@ -1438,7 +1529,7 @@ def acl_check(name = 'test', tool = '', topic_num = '1'):
     get_ban = ban_check()
     
     if tool == '' and name:
-        if tool == '' and acl_check(name, 'render') == 1:
+        if acl_check(name, 'render') == 1:
             return 1
         
         user_page = re.search(r"^user:((?:(?!\/).)*)", name)
@@ -1463,6 +1554,9 @@ def acl_check(name = 'test', tool = '', topic_num = '1'):
             if ip == user_page and not ip_or_user(ip) == 1:
                 return 0
     
+            return 1
+    elif tool == 'document_edit' or tool == 'document_move' or tool == 'document_delete':
+        if acl_check(name, '') == 1:
             return 1
     elif tool == 'topic':
         curs.execute(db_change("select title from rd where code = ?"), [topic_num])
@@ -1493,6 +1587,24 @@ def acl_check(name = 'test', tool = '', topic_num = '1'):
                     'select data from other where name = "edit"'
                 ))
 
+            num = 5
+        elif tool == 'document_move':
+            curs.execute(db_change(
+                "select data from acl where title = ? and type = 'document_move_acl'"
+            ), [name])
+
+            num = 5
+        elif tool == 'document_edit':
+            curs.execute(db_change(
+                "select data from acl where title = ? and type = 'document_edit_acl'"
+            ), [name])
+
+            num = 5
+        elif tool == 'document_delete':
+            curs.execute(db_change(
+                "select data from acl where title = ? and type = 'document_delete_acl'"
+            ), [name])
+
             num = 5
         elif tool == 'topic':
             if i == 0:
@@ -1508,6 +1620,12 @@ def acl_check(name = 'test', tool = '', topic_num = '1'):
                     'select data from other where name = "discussion"'
                 ))
 
+            num = 3
+        elif tool == 'topic_view':
+            curs.execute(db_change("select set_data from topic_set where thread_code = ? and set_name = 'thread_view_acl'"), [
+                topic_num
+            ])
+            
             num = 3
         elif tool == 'upload':
             curs.execute(db_change(
@@ -1549,9 +1667,11 @@ def acl_check(name = 'test', tool = '', topic_num = '1'):
         elif acl_data and acl_data[0][0] == '':
             acl_data = [['normal']]
 
+        except_ban_tool_list = ['render', 'topic_view']
         if acl_data[0][0] != 'normal':
-            if not acl_data[0][0] in ['ban', 'ban_admin'] and get_ban == 1 and tool != 'render':
-                return 1
+            if not acl_data[0][0] in ['ban', 'ban_admin'] and not tool in except_ban_tool_list:
+                if get_ban == 1:
+                    return 1
             
             if acl_data[0][0] in ['all', 'ban']:
                 return 0
@@ -1626,8 +1746,9 @@ def acl_check(name = 'test', tool = '', topic_num = '1'):
 
             return 1
         elif i == (end - 1):
-            if get_ban == 1 and tool != 'render':
-                return 1
+            if not tool in except_ban_tool_list:
+                if get_ban == 1:
+                    return 1
             
             if tool == 'topic':
                 curs.execute(db_change(
@@ -1790,8 +1911,8 @@ def do_edit_slow_check():
 
     curs.execute(db_change("select data from other where name = 'slow_edit'"))
     slow_edit = curs.fetchall()
-    if slow_edit and slow_edit != '0' and admin_check(5) != 1:
-        slow_edit = slow_edit[0][0]
+    if slow_edit and slow_edit != '' and admin_check(5) != 1:
+        slow_edit = int(number_check(slow_edit[0][0]))
 
         curs.execute(db_change(
             "select date from history where ip = ? order by date desc limit 1"
@@ -1799,11 +1920,9 @@ def do_edit_slow_check():
         last_edit_data = curs.fetchall()
         if last_edit_data:
             last_edit_data = int(re.sub(' |:|-', '', last_edit_data[0][0]))
-            now_edit_data = int(
-                (datetime.datetime.now() - datetime.timedelta(
-                    seconds = int(slow_edit))
-                ).strftime("%Y%m%d%H%M%S")
-            )
+            now_edit_data = int((
+                datetime.datetime.now() - datetime.timedelta(seconds = slow_edit)
+            ).strftime("%Y%m%d%H%M%S"))
 
             if last_edit_data > now_edit_data:
                 return 1
@@ -1832,19 +1951,70 @@ def do_edit_filter(data):
 
     return 0
 
-def do_title_length_check(name):
+def do_title_length_check(name, check_type = 'document'):
     curs = conn.cursor()
     
-    curs.execute(db_change('select data from other where name = "title_max_length"'))
-    db_data = curs.fetchall()
-    if db_data and db_data[0][0] != '':
-        db_data = int(number_check(db_data[0][0]))
-        if len(name) > db_data:        
-            return 1
+    if check_type == 'topic':
+        curs.execute(db_change('select data from other where name = "title_topic_max_length"'))
+        db_data = curs.fetchall()
+        if db_data and db_data[0][0] != '':
+            db_data = int(number_check(db_data[0][0]))
+            if len(name) > db_data:        
+                return 1
+    else:
+        curs.execute(db_change('select data from other where name = "title_max_length"'))
+        db_data = curs.fetchall()
+        if db_data and db_data[0][0] != '':
+            db_data = int(number_check(db_data[0][0]))
+            if len(name) > db_data:        
+                return 1
     
     return 0
 
 # Func-insert
+def do_add_thread(thread_code, thread_data, thread_top = '', thread_id = ''):
+    curs = conn.cursor()
+    
+    if thread_id == '':
+        curs.execute(db_change("select id from topic where code = ? order by id + 0 desc limit 1"), [thread_code])
+        db_data = curs.fetchall()
+        if db_data:
+            thread_id = str(int(db_data[0][0]) + 1)
+        else:
+            thread_id = '1'
+        
+    curs.execute(db_change("insert into topic (id, data, date, ip, block, top, code) values (?, ?, ?, ?, ?, '', ?)"), [
+        thread_id,
+        thread_data,
+        get_time(),
+        ip_check(),
+        thread_top,
+        thread_code
+    ])
+    
+    conn.commit()
+    
+def do_reload_recent_thread(topic_num, date, name = None, sub = None):
+    curs = conn.cursor()
+
+    curs.execute(db_change("select code from rd where code = ?"), [topic_num])
+    if curs.fetchall():
+        curs.execute(db_change("update rd set date = ? where code = ?"), [
+            date, 
+            topic_num
+        ])
+    else:
+        curs.execute(db_change(
+            "insert into rd (title, sub, code, date, band, stop, agree, acl) values (?, ?, ?, ?, '', '', '', '')"
+        ), [
+            name, 
+            sub, 
+            topic_num, 
+            date
+        ])
+
+    conn.commit()
+
 def add_alarm(who, context):
     curs = conn.cursor()
 
@@ -1969,21 +2139,13 @@ def ban_insert(name, end, why, login, blocker, type_d = None):
 
     conn.commit()
 
-def rd_plus(topic_num, date, name = None, sub = None):
-    curs = conn.cursor()
-
-    curs.execute(db_change("select code from rd where code = ?"), [topic_num])
-    if curs.fetchall():
-        curs.execute(db_change("update rd set date = ? where code = ?"), [date, topic_num])
-    else:
-        curs.execute(db_change(
-            "insert into rd (title, sub, code, date, band, stop, agree, acl) values (?, ?, ?, ?, '', '', '', '')"
-        ), [name, sub, topic_num, date])
-
-    conn.commit()
-
 def history_plus(title, data, date, ip, send, leng, t_check = '', mode = ''):
     curs = conn.cursor()
+    
+    curs.execute(db_change('select data from other where name = "history_recording_off"'))
+    db_data = curs.fetchall()
+    if db_data and db_data[0][0] != '':
+        return 0
 
     if mode == 'add':
         curs.execute(db_change(
@@ -2074,12 +2236,12 @@ def re_error(data):
 
     if data == '/ban':
         if ban_check() == 1:
-            end = '<div id="get_user_info"></div><script>load_user_info("' + ip_check() + '");</script>'
+            end = '<div id="opennamu_get_user_info">' + ip_check() + '</div>'
         else:
             end = '<ul class="inside_ul"><li>' + load_lang('authority_error') + '</li></ul>'
 
         return easy_minify(flask.render_template(skin_check(),
-            imp = [load_lang('error'), wiki_set(1), wiki_custom(), wiki_css([0, 0])],
+            imp = [load_lang('error'), wiki_set(), wiki_custom(), wiki_css([0, 0])],
             data = '<h2>' + load_lang('error') + '</h2>' + end,
             menu = 0
         )), 401
@@ -2118,11 +2280,15 @@ def re_error(data):
         elif num == 16:
             data = load_lang('same_file_error')
         elif num == 17:
-            data = load_lang('file_capacity_error') + wiki_set(3)
+            curs.execute(db_change('select data from other where name = "upload"'))
+            db_data = curs.fetchall()
+            file_max = int(number_check(db_data[0][0])) if db_data and db_data[0][0] != '' else '2'
+
+            data = load_lang('file_capacity_error') + file_max
         elif num == 18:
             data = load_lang('email_send_error')
         elif num == 19:
-            data = load_lang('decument_exist_error')
+            data = load_lang('move_error')
         elif num == 20:
             data = load_lang('password_diffrent_error')
         elif num == 21:
@@ -2168,6 +2334,15 @@ def re_error(data):
             db_data = curs.fetchall()
             db_data = '' if not db_data else db_data[0][0]
             data = load_lang('error_title_length_too_long') + db_data
+        elif num == 40:
+            curs.execute(db_change("select data from other where name = 'password_min_length'"))
+            db_data = curs.fetchall()
+            if db_data and db_data[0][0] != '':
+                password_min_length = db_data[0][0]
+            else:
+                password_min_length = ''
+                
+            data = load_lang('error_password_length_too_short') + password_min_length
         else:
             data = '???'
 
@@ -2177,15 +2352,15 @@ def re_error(data):
                     data += '<br>' + load_lang('error_skin_set_old') + ' <a href="/skin_set">(' + load_lang('go') + ')</a>'
 
                 title = load_lang('skin_set')
-                tool = [['change', load_lang('user_setting')]]
+                tool = [['change', load_lang('user_setting')], ['change/skin_set/main', load_lang('main_skin_set')]]
                 load_skin_set = ''
             else:
                 title = load_lang('main_skin_set')
-                tool = [['change', load_lang('user_setting')]]
+                tool = [['change', load_lang('user_setting')], ['change/skin_set', load_lang('skin_set')]]
                 load_skin_set = '<script>main_css_skin_set();</script>'
         
             return easy_minify(flask.render_template(skin_check(),
-                imp = [title, wiki_set(1), wiki_custom(), wiki_css([0, 0])],
+                imp = [title, wiki_set(), wiki_custom(), wiki_css([0, 0])],
                 data = '' + \
                     '<div id="main_skin_set">' + \
                         '<h2>' + load_lang('error') + '</h2>' + \
@@ -2198,7 +2373,7 @@ def re_error(data):
             ))
         else:
             return easy_minify(flask.render_template(skin_check(),
-                imp = [load_lang('error'), wiki_set(1), wiki_custom(), wiki_css([0, 0])],
+                imp = [load_lang('error'), wiki_set(), wiki_custom(), wiki_css([0, 0])],
                 data = '' + \
                      '<h2>' + load_lang('error') + '</h2>' + \
                      '<ul class="inside_ul">' + \

+ 19 - 30
route/tool/func_render.py

@@ -3,8 +3,10 @@ from .func_render_namumark import *
 # 커스텀 마크 언젠간 다시 추가 예정
 
 class class_do_render:
-    def __init__(self, conn):
+    def __init__(self, conn, lang_data):
         self.conn = conn
+
+        self.lang_data = lang_data
     
     def do_backlink_generate(self, data_markup, doc_data, doc_name):
         conn = self.conn
@@ -104,7 +106,13 @@ class class_do_render:
         conn = self.conn
         curs = self.conn.cursor()
 
-        data_in = None if data_in == '' else data_in
+        doc_set = {}
+        if data_in == 'from':
+            data_in = ''
+            doc_set['doc_from'] = 'O'
+        
+        data_in = (data_in + '_') if data_in != '' else ''
+        doc_set['doc_include'] = data_in
 
         curs.execute(db_change('select data from other where name = "markup"'))
         rep_data = curs.fetchall()
@@ -112,7 +120,6 @@ class class_do_render:
 
         if data_type != 'backlink':
             if rep_data == 'namumark':
-                data_in = (data_in + '_') if data_in else ''
                 doc_data = html.escape(doc_data)
                 doc_name = html.escape(doc_name)
                 
@@ -127,46 +134,28 @@ class class_do_render:
                             name_doc = "''' + doc_name + '''"
                         );
                     ''',
-                    []
+                    {}
                 ]
             elif rep_data == 'namumark_beta':
-                doc_include = (data_in + '_') if data_in else ''
                 data_end = class_do_render_namumark(
                     curs,
                     doc_name,
                     doc_data,
-                    doc_include
+                    doc_set,
+                    self.lang_data
                 )()
-            elif rep_data == 'markdown':
-                data_in = (data_in + '_') if data_in else ''
-                doc_data = html.escape(doc_data)
-                doc_name = html.escape(doc_name)
-                
-                data_end = [
-                    '<pre class="render_content_load" id="' + data_in + 'render_content_load">' + html.escape(doc_data) + '</pre>' + \
-                    '<div class="render_content" id="' + data_in + 'render_content" style="display: none;"></div>', 
-                    'new opennamu_render_markdown(' + \
-                        'render_part_id = "render_content_load",' + \
-                        'render_part_id_after = "render_content",' + \
-                        'render_part_id_add = "' + data_in + '",' + \
-                        'doc_name = "' + doc_name + '"' + \
-                    ').do_main();',
-                    []
-                ]
             else:
                 data_end = [
                     doc_data, 
                     '', 
-                    []
+                    {}
                 ]
 
-            if data_type == 'api_view':
-                return [
-                    data_end[0], 
-                    data_end[1]
-                ]
-            else:
-                return data_end[0] + '<script>' + data_end[1] + '</script>'
+            return [
+                data_end[0], 
+                data_end[1],
+                data_end[2]
+            ]
         else:
             if rep_data == 'namumark':
                 backlink = self.do_backlink_generate(

+ 1001 - 79
route/tool/func_render_namumark.py

@@ -1,115 +1,1037 @@
 from .func_tool import *
 
 class class_do_render_namumark:
-    def __init__(
-        self,
-        curs,
-        doc_name, 
-        doc_data, 
-        doc_include
-    ):
+    def __init__(self, curs, doc_name, doc_data, doc_set, lang_data):
         self.curs = curs
         
         self.doc_data = doc_data
         self.doc_name = doc_name
-        self.doc_include = doc_include
-        
-        self.data_nowiki = {}
+        self.doc_set = doc_set
+        self.doc_include = self.doc_set['doc_include'] if 'doc_include' in self.doc_set else ''
+
+        self.lang_data = lang_data
+
+        self.data_temp_storage = {}
+        self.data_temp_storage_count = 0
+
         self.data_backlink = []
+        self.data_include = []
+
+        self.data_math_count = 0
         
         self.data_toc = ''
-        self.data_footnote = ''
+        self.data_footnote = {}
         self.data_category = ''
 
+        self.render_data = self.doc_data
+        self.render_data = html.escape(self.render_data)
+        self.render_data = '<back_br>\n' + self.render_data + '\n<front_br>'
+        self.render_data_js = ''
+
+    def get_tool_lang(self, name):
+        if name in self.lang_data:
+            return self.lang_data[name]
+        else:
+            return name + ' (RENDER LANG)'
+
+    def get_tool_js_safe(self, data):
+        data = re.sub(r'\\', '\\\\\\\\', data)
+        data = re.sub(r'"', '\\"', data)
+        data = re.sub(r'\n', '\\n', data)
+
+        return data
+
+    def get_tool_data_storage(self, data_A = '', data_B = '', data_C = '', do_type = 'render'):
+        self.data_temp_storage_count += 1
+        if do_type == 'render':
+            data_name = 'render_' + str(self.data_temp_storage_count)
+
+            self.data_temp_storage[data_name] = data_A
+            self.data_temp_storage['/' + data_name] = data_B
+            self.data_temp_storage['revert_' + data_name] = data_C
+        else:
+            data_name = 'slash_' + str(self.data_temp_storage_count)
+
+            self.data_temp_storage[data_name] = data_A
+
+        return data_name
+
+    def get_tool_data_restore(self, data, do_type = 'all'):
+        storage_count = self.data_temp_storage_count * 3
+        if do_type == 'all':
+            storage_regex = r'<(\/?(?:render|slash)_(?:[0-9]+))>'
+        elif do_type == 'render':
+            storage_regex = r'<(\/?(?:render)_(?:[0-9]+))>'
+        else:
+            storage_regex = r'<(\/?(?:slash)_(?:[0-9]+))>'
+
+        while 1:
+            if not re.search(storage_regex, data):
+                break
+            if storage_count < 0:
+                print('Error : render restore count overflow')
+
+                break
+            else:
+                data = re.sub(storage_regex, lambda match : self.data_temp_storage[match.group(1)], data, 1)
+
+            storage_count -= 1
+
+        return data
+
+    def get_tool_data_revert(self, data):
+        storage_count = self.data_temp_storage_count * 2
+        storage_regex = r'<(render_(?:[0-9]+))>(?:(?:(?!<(?:\/?render_(?:[0-9]+))>).)*)<\/render_(?:[0-9]+)>'
+
+        while 1:
+            if not re.search(storage_regex, data):
+                break
+            if storage_count < 0:
+                print('Error : render restore count overflow')
+
+                break
+            else:
+                data = re.sub(storage_regex, lambda match : self.data_temp_storage['revert_' + match.group(1)], data, 1)
+
+            storage_count -= 1
+
+        return data
+
+    def get_tool_footnote_make(self):
+        data = ''
+        for for_a in self.data_footnote:
+            if data == '':
+                data += '<div class="opennamu_footnote">'
+            else:
+                data += '<br>'
+
+            if len(self.data_footnote[for_a]['list']) > 1:
+                data += '(' + for_a + ') '
+
+                for for_b in self.data_footnote[for_a]['list']:
+                    data += '<sup><a id="' + self.doc_include + 'fn_' + for_b + '" href="#' + self.doc_include + 'rfn_' + for_b + '">(' + for_b + ')</a></sup> '
+            else:
+                data += '<a id="' + self.doc_include + 'fn_' + self.data_footnote[for_a]['list'][0] + '" href="#' + self.doc_include + 'rfn_' + self.data_footnote[for_a]['list'][0] + '">(' + for_a + ') </a> '
+
+            data += self.data_footnote[for_a]['data']
+
+        if data != '':
+            data += '</div>'
+
+        self.data_footnote = {}
+
+        return data
+
     def do_render_text(self):
+        # <b> function
+        bold_user_set = flask.request.cookies.get('main_css_del_bold', '0')
+        def do_render_text_bold(match):
+            data = match.group(1)
+            if bold_user_set == '0':
+                data_name = self.get_tool_data_storage('<b>', '</b>', match.group(0))
+            elif bold_user_set == '1':
+                data_name = self.get_tool_data_storage('', '', match.group(0))
+            else:
+                return ''
+            
+            return '<' + data_name + '>' + data + '</' + data_name + '>'
+
         # <b>
-        self.render_data = re.sub(
-            r"&#x27;&#x27;&#x27;((?:(?!&#x27;&#x27;&#x27;).)+)&#x27;&#x27;&#x27;",
-            '<b>\g<1></b>',
-            self.render_data
-        )
+        self.render_data = re.sub(r"&#x27;&#x27;&#x27;((?:(?!&#x27;&#x27;&#x27;).)+)&#x27;&#x27;&#x27;", do_render_text_bold, self.render_data)
+
+        # <i> function
+        def do_render_text_italic(match):
+            data = match.group(1)
+            data_name = self.get_tool_data_storage('<i>', '</i>', match.group(0))
+            
+            return '<' + data_name + '>' + data + '</' + data_name + '>'
+
         # <i>
-        self.render_data = re.sub(
-            r"&#x27;&#x27;((?:(?!&#x27;&#x27;).)+)&#x27;&#x27;",
-            '<i>\g<1></i>',
-            self.render_data
-        )
+        self.render_data = re.sub(r"&#x27;&#x27;((?:(?!&#x27;&#x27;).)+)&#x27;&#x27;", do_render_text_italic, self.render_data)
+
+        # <u> function
+        def do_render_text_under(match):
+            data = match.group(1)
+            data_name = self.get_tool_data_storage('<u>', '</u>', match.group(0))
+            
+            return '<' + data_name + '>' + data + '</' + data_name + '>'
+
         # <u>
-        self.render_data = re.sub(
-            r"__((?:(?!__).)+)__",
-            '<u>\g<1></u>',
-            self.render_data
-        )
+        self.render_data = re.sub(r"__((?:(?!__).)+)__", do_render_text_under, self.render_data)
         
+        # <sup> function
+        def do_render_text_sup(match):
+            data = match.group(1)
+            data_name = self.get_tool_data_storage('<sup>', '</sup>', match.group(0))
+            
+            return '<' + data_name + '>' + data + '</' + data_name + '>'
+
         # <sup>
-        self.render_data = re.sub(
-            r"\^\^\^((?:(?!\^\^\^).)+)\^\^\^",
-            '<sup>\g<1></sup>',
-            self.render_data
-        )
+        self.render_data = re.sub(r"\^\^\^((?:(?!\^\^\^).)+)\^\^\^", do_render_text_sup, self.render_data)
         # <sup> 2
-        self.render_data = re.sub(
-            r"\^\^((?:(?!\^\^).)+)\^\^",
-            '<sup>\g<1></sup>',
-            self.render_data
-        )
+        self.render_data = re.sub(r"\^\^((?:(?!\^\^).)+)\^\^", do_render_text_sup, self.render_data)
+
+        # <sub> function
+        def do_render_text_sub(match):
+            data = match.group(1)
+            data_name = self.get_tool_data_storage('<sub>', '</sub>', match.group(0))
+            
+            return '<' + data_name + '>' + data + '</' + data_name + '>'
         
         # <sub>
-        self.render_data = re.sub(
-            r",,,((?:(?!,,,).)+),,,",
-            '<sub>\g<1></sub>',
-            self.render_data
-        )
+        self.render_data = re.sub(r",,,((?:(?!,,,).)+),,,", do_render_text_sub, self.render_data)
         # <sub> 2
-        self.render_data = re.sub(
-            r",,((?:(?!,,).)+),,",
-            '<sub>\g<1></sub>',
-            self.render_data
-        )
+        self.render_data = re.sub(r",,((?:(?!,,).)+),,", do_render_text_sub, self.render_data)
+
+        # <sub> function
+        strike_user_set = flask.request.cookies.get('main_css_del_strike', '0')
+        def do_render_text_strike(match):
+            data = match.group(1)
+            if bold_user_set == '0':
+                data_name = self.get_tool_data_storage('<s>', '</s>', match.group(0))
+            elif bold_user_set == '1':
+                data_name = self.get_tool_data_storage('', '', match.group(0))
+            else:
+                return ''
+            
+            return '<' + data_name + '>' + data + '</' + data_name + '>'
         
         # <s>
-        self.render_data = re.sub(
-            r"--((?:(?!--).)+)--",
-            '<s>\g<1></s>',
-            self.render_data
-        )
+        self.render_data = re.sub(r"--((?:(?!--).)+)--", do_render_text_strike, self.render_data)
         # <s> 2
-        self.render_data = re.sub(
-            r"~~((?:(?!~~).)+)~~",
-            '<s>\g<1></s>',
-            self.render_data
-        )
+        self.render_data = re.sub(r"~~((?:(?!~~).)+)~~", do_render_text_strike, self.render_data)
+    
+    def do_render_heading(self):
+        toc_list = []
+
+        # make heading base
+        heading_regex = r'\n((={1,6})(#?) ?([^\n]+))\n'
+        heading_count_all = len(re.findall(heading_regex, self.render_data)) * 3
+        heading_stack = [0, 0, 0, 0, 0, 0]
+        while 1:
+            if not re.search(heading_regex, self.render_data):
+                break
+            elif heading_count_all < 0:
+                print('Error : render heading count overflow')
+
+                break
+            else:
+                heading_data = re.search(heading_regex, self.render_data)
+                heading_data = heading_data.groups()
+
+                heading_data_last_regex = r' ?(#?={1,6})$'
+                heading_data_last = re.search(heading_data_last_regex, heading_data[3])
+                heading_data_last = heading_data_last.group(1)
+                heading_data_text = re.sub(heading_data_last_regex, '', heading_data[3])
+
+                heading_data_diff = heading_data[2] + heading_data[1]
+                if heading_data_diff != heading_data_last:
+                    # front != back -> restore
+
+                    heading_data_all = heading_data[0]
+
+                    for for_a in reversed(range(1, 7)):
+                        for_a_str = str(for_a)
+
+                        heading_restore_regex = re.compile('^={' + for_a_str + '}|={' + for_a_str + '}$')
+
+                        heading_data_all = re.sub(heading_restore_regex, '<heading_' + for_a_str + '>', heading_data_all)
+
+                    self.render_data = re.sub(heading_regex, '\n' + heading_data_all + '\n', self.render_data, 1)
+                else:
+                    heading_level = len(heading_data[1])
+                    heading_level_str = str(heading_level)
+
+                    heading_stack[heading_level - 1] += 1
+                    for for_a in range(heading_level, 6):
+                        heading_stack[for_a] = 0
+
+                    heading_stack_str = '.'.join([str(for_a) for for_a in heading_stack])
+                    heading_stack_str = re.sub(r'(\.0)+$', '', heading_stack_str)
+
+                    toc_list += [['', heading_data_text]]
+
+                    heading_data_text_fix = re.sub(r'<([^<>]*)>', '', heading_data_text)
+                    
+                    data_name = self.get_tool_data_storage('<h' + heading_level_str + ' id="' + heading_data_text_fix + '">', '</h' + heading_level_str + '>', '')
+
+                    heading_data_complete = '' + \
+                        '\n<front_br>' + \
+                        '<' + data_name + '>' + \
+                            '<heading_stack>' + \
+                                heading_stack_str + \
+                            '</heading_stack>' + \
+                            ' ' + heading_data_text + \
+                        '</' + data_name + '>' + \
+                        '<back_br>\n' + \
+                    ''
+
+                    self.render_data = re.sub(heading_regex, heading_data_complete, self.render_data, 1)
+
+            heading_count_all -= 1
+
+        # heading id adjust
+        heading_end_count = len(re.findall(r'<heading_stack>', self.render_data))
+        for for_a in reversed(range(0, 6)):
+            heading_end_stack_regex = re.compile('<heading_stack>' + ('0\\.' * for_a))
+
+            heading_end_match_count = len(re.findall(heading_end_stack_regex, self.render_data))
+            if heading_end_match_count == heading_end_count:
+                self.render_data = re.sub(heading_end_stack_regex, '<heading_stack>', self.render_data)
+
+                break
+
+        # heading id -> inline id
+        heading_id_regex = r'<heading_stack>([^<>]+)<\/heading_stack>'
+        heading_id_data = re.findall(heading_id_regex, self.render_data)
+        for for_a in range(len(heading_id_data)):
+            self.render_data = re.sub(heading_id_regex, '<a href="#toc" id="s-' + heading_id_data[for_a] + '">' + heading_id_data[for_a] + '.</a>', self.render_data, 1)
+            
+            toc_list[for_a][0] = heading_id_data[for_a]
+
+        # not heading restore
+        for for_a in range(1, 7):
+            for_a_str = str(for_a)
+
+            heading_restore_regex = re.compile('<heading_' + for_a_str + '>')
+
+            self.render_data = re.sub(heading_restore_regex, ('=' * for_a), self.render_data)
+
+        # make toc
+        if len(toc_list) == 0:
+            toc_data = ''
+        else:
+            toc_data = '' + \
+                '<div class="opennamu_TOC" id="toc">' + \
+                    '<span class="opennamu_TOC_title">' + self.get_tool_lang('toc') + '</span>' + \
+                    '<br>' + \
+                ''
+
+        for for_a in toc_list:
+            toc_data += '' + \
+                '<br>' + \
+                ('<span style="margin-left: 10px;">' * for_a[0].count('.')) + \
+                '<span>' + \
+                    '<a href="#s-' + for_a[0] + '">' + \
+                        for_a[0] + '. ' + \
+                    '</a>' + \
+                    for_a[1] + \
+                '</span>' + \
+            ''
+
+        if toc_data != '':
+            toc_data += '</div>'
+
+        # toc replace
+        self.render_data = re.sub(r'\[(목차|toc|tableofcontents)\]', toc_data, self.render_data)
+
+    def do_render_macro(self):
+        # double macro function
+        def do_render_macro_double(match):
+            match_org = match
+            match = match.groups()
+
+            name_data = match[0]
+            macro_split_regex = r'(?:^|,) *([^,]+)'
+            macro_split_sub_regex = r'(^[^=]+) *= *([^=]+)'
+            if name_data in ('youtube', 'nicovideo', 'navertv', 'kakaotv', 'vimeo'):
+                data = re.findall(macro_split_regex, match[1])
+
+                # get option
+                video_code = ''
+                video_start = ''
+                video_end = ''
+                video_width = '640px'
+                video_height = '360px'
+                for for_a in data:
+                    data_sub = re.search(macro_split_sub_regex, for_a)
+                    if data_sub:
+                        data_sub = data_sub.groups()
+                        if data_sub[0] == 'width':
+                            if re.search(r'^[0-9]+$', data_sub[1]):
+                                video_width = data_sub[1] + 'px'
+                            else:
+                                video_width = data_sub[1]
+                        elif data_sub[0] == 'height':
+                            if re.search(r'^[0-9]+$', data_sub[1]):
+                                video_height = data_sub[1] + 'px'
+                            else:
+                                video_height = data_sub[1]
+                        elif data_sub[0] == 'start':
+                            video_start = data_sub[1]
+                        elif data_sub[0] == 'end':
+                            video_end = data_sub[1]
+                        elif data_sub[0] == 'https://www.youtube.com/watch?v' and name_data == 'youtube':
+                            video_code = data_sub[1]
+                    else:
+                        video_code = for_a
+
+                # code to url
+                if name_data == 'youtube':
+                    video_code = re.sub(r'^https:\/\/youtu\.be\/', '', video_code)
+
+                    video_code = 'https://www.youtube.com/embed/' + video_code
+
+                    if video_start != '':
+                        if video_end != '':
+                            video_code += '?start=' + video_start + '&end=' + video_end
+                        else:
+                            video_code += '?start=' + video_start
+                    else:
+                        if video_end != '':
+                            video_code += '?end=' + video_end
+                elif name_data == 'kakaotv':
+                    video_code = re.sub(r'^https:\/\/tv\.kakao\.com\/v\/', '', video_code)
+
+                    video_code = 'https://tv.kakao.com/embed/player/cliplink/' + video_code +'?service=kakao_tv'
+                elif name_data == 'navertv':
+                    video_code = re.sub(r'^https:\/\/tv\.naver\.com\/v\/', '', video_code)
+
+                    video_code = 'https://tv.naver.com/embed/' + video_code
+                elif name_data == 'nicoviedo':
+                    video_code = 'https://embed.nicovideo.jp/watch/' + video_code
+                else:
+                    video_code = 'https://player.vimeo.com/video/' + video_code
+
+                data_name = self.get_tool_data_storage('<iframe style="width: ' + video_width + '; height: ' + video_height + ';" src="' + video_code + '" frameborder="0" allowfullscreen></iframe>', '', match_org.group(0))
+
+                return '<' + data_name + '></' + data_name + '>'
+            elif name_data == 'ruby':
+                data = re.findall(macro_split_regex, match[1])
+
+                # get option
+                main_text = ''
+                sub_text = ''
+                color = ''
+                for for_a in data:
+                    data_sub = re.search(macro_split_sub_regex, for_a)
+                    if data_sub:
+                        data_sub = data_sub.groups()
+                        if data_sub[0] == 'ruby':
+                            sub_text = data_sub[1]
+                        elif data_sub[0] == 'color':
+                            color = data_sub[1]
+                    else:
+                        main_text = for_a
+
+                main_text = self.get_tool_data_revert(main_text)
+                sub_text = self.get_tool_data_revert(sub_text)
+
+                # add color
+                if color != '':
+                    sub_text = '<span style="color:' + color + ';">' + sub_text + '</span>'
+
+                data_name = self.get_tool_data_storage('<ruby>' + main_text + '<rp>(</rp><rt>' + sub_text + '</rt><rp>)</rp></ruby>', '', match_org.group(0))
+
+                return '<' + data_name + '></' + data_name + '>'
+            elif name_data == 'age':
+                if re.search(r'^[0-9]{4}-[0-9]{2}-[0-9]{2}$', match[1]):
+                    try:
+                        date = datetime.datetime.strptime(match[1], '%Y-%m-%d')
+                    except:
+                        data_text = 'invalid date'
+
+                    date_now = datetime.datetime.today()
+
+                    if date > date_now:
+                        data_text = 'invalid date'
+                    else:
+                        data_text = str((date_now - date).days // 365)
+                else:
+                    data_text = 'invalid date'
+
+                data_name = self.get_tool_data_storage(data_text, '', match_org.group(0))
+
+                return '<' + data_name + '></' + data_name + '>'
+            elif name_data == 'dday':
+                if re.search(r'^[0-9]{4}-[0-9]{2}-[0-9]{2}$', match[1]):
+                    try:
+                        date = datetime.datetime.strptime(match[1], '%Y-%m-%d')
+                    except:
+                        data_text = 'invalid date'
+
+                    date_now = datetime.datetime.today()
+                    
+                    date_end = (date_now - date).days
+                    if date_end > 0:
+                        data_text = '+' + str(date_end)
+                    else:
+                        if date_end == 0:
+                            data_text = '-' + str(date_end)
+                        else:
+                            data_text = str(date_end)
+                else:
+                    data_text = 'invalid date'
+
+                data_name = self.get_tool_data_storage(data_text, '', match_org.group(0))
+
+                return '<' + data_name + '></' + data_name + '>'
+            else:
+                return '<macro>' + match[0] + '(' + match[1] + ')' + '</macro>'
+
+        # double macro replace
+        self.render_data = re.sub(r'\[([^[(]+)\(([^()]+)\)\]', do_render_macro_double, self.render_data)
+
+        # single macro function
+        def do_render_macro_single(match):
+            match_org = match
+            match = match.group(1)
+
+            if match in ('date', 'datetime'):
+                data_name = self.get_tool_data_storage(get_time(), '', match_org.group(0))
+
+                return '<' + data_name + '></' + data_name + '>'
+            elif match == 'br':
+                data_name = self.get_tool_data_storage('<br>', '', match_org.group(0))
+
+                return '<' + data_name + '></' + data_name + '>'
+            elif match == 'clearfix':
+                data_name = self.get_tool_data_storage('<div style="clear: both;"></div>', '', match_org.group(0))
+
+                return '<' + data_name + '></' + data_name + '>'
+            else:
+                return '<macro>' + match + '</macro>'
+
+        # single macro replace
+        self.render_data = re.sub(r'\[([^[\]]+)\]', do_render_macro_single, self.render_data)
+
+        # macro safe restore
+        self.render_data = re.sub(r'<macro>', '[', self.render_data)
+        self.render_data = re.sub(r'<\/macro>', ']', self.render_data)
+
+    def do_render_math(self):
+        def do_render_math_sub(match):
+            data = self.get_tool_data_restore(match.group(1), do_type = 'slash')
+            data = html.unescape(data)
+            data = self.get_tool_js_safe(data)
+
+            data_html = self.get_tool_js_safe(match.group(1))
+
+            name_ob = 'opennamu_math_' + str(self.data_math_count)
+
+            data_name = self.get_tool_data_storage('<span id="' + name_ob + '">', '</span>', match.group(0))
+
+            self.render_data_js += '' + \
+                'try {\n' + \
+                    'katex.render("' + data + '", document.getElementById(\"' + name_ob + '\"));\n' + \
+                '} catch {\n' + \
+                    'document.getElementById(\"' + name_ob + '\").innerHTML = "<span style=\'color: red;\'>' + data_html + '</span>";\n' + \
+                '}\n' + \
+            ''
+
+            self.data_math_count += 1
+
+            return '<' + data_name + '></' + data_name + '>'
+
+        self.render_data = re.sub(r'\[math\(((?:(?!\)\]).)+)\)\]', do_render_math_sub, self.render_data)
+
+    def do_render_link(self):
+        # todo list
+        # add link exist check
+        # add file exist check
+
+        link_regex = r'\[\[((?:(?!\[\[|\]\]|\||<|>).|<slash_[0-9]+>)+)(?:\|((?:(?!\[\[|\]\]|\|).)+))?\]\]'
+        link_count_all = len(re.findall(link_regex, self.render_data)) * 4
+        while 1:
+            if not re.search(link_regex, self.render_data):
+                break
+            elif link_count_all < 0:
+                print('Error : render heading count overflow')
+
+                break
+            else:
+                # link split
+                link_data = re.search(link_regex, self.render_data)
+                link_data_full = link_data.group(0)
+                link_data = link_data.groups()
+
+                link_main = link_data[0]
+                link_main_org = link_main
+
+                # file link
+                if re.search(r'^(파일|file|외부|out):', link_main):
+                    file_width = ''
+                    file_height = ''
+                    file_align = ''
+                    file_bgcolor = ''
+
+                    file_split_regex = r'(?:^|&amp;) *((?:(?!&amp;).)+)'
+                    file_split_sub_regex = r'(^[^=]+) *= *([^=]+)'
+                    if link_data[1]:
+                        data = re.findall(file_split_regex, link_data[1])
+                        for for_a in data:
+                            data_sub = re.search(file_split_sub_regex, for_a)
+                            if data_sub:
+                                data_sub = data_sub.groups()
+                                if data_sub[0] == 'width':
+                                    if re.search(r'^[0-9]+$', data_sub[1]):
+                                        file_width = data_sub[1] + 'px'
+                                    else:
+                                        file_width = data_sub[1]
+                                elif data_sub[0] == 'height':
+                                    if re.search(r'^[0-9]+$', data_sub[1]):
+                                        file_height = data_sub[1] + 'px'
+                                    else:
+                                        file_height = data_sub[1]
+                                elif data_sub[0] == 'align':
+                                    if data_sub[1] in ('left', 'right'):
+                                        file_align = 'float:' + data_sub[1] + ';'
+                                    elif data_sub[1] == 'center':
+                                        file_align = 'center'
+                                elif data_sub[0] == 'bgcolor':
+                                    file_bgcolor = data_sub[1]
+
+                    link_main_org = ''
+                    link_sub = link_main
+
+                    link_out_regex = r'^(외부|out):'
+                    link_in_regex = r'^(파일|file):'
+                    if re.search(link_out_regex, link_main):
+                        link_main = re.sub(link_out_regex, '', link_main)
+
+                        link_main = self.get_tool_data_restore(link_main, do_type = 'slash')
+                        link_main = html.unescape(link_main)
+                        link_main = re.sub(r'"', '&quot;', link_main)
+                        
+                        link_exist = ''
+                    else:
+                        link_main = re.sub(link_in_regex, '', link_main)
+
+                        link_main = self.get_tool_data_restore(link_main, do_type = 'slash')
+                        link_main = html.unescape(link_main)
+
+                        self.curs.execute(db_change("select title from data where title = ?"), ['file:' + link_main])
+                        db_data = self.curs.fetchall()
+                        if db_data:
+                            link_exist = ''
+                        else:
+                            link_exist = 'opennamu_not_exist_link'
+                        
+                        link_extension_regex = r'\.([^.]+)$'
+                        link_extension = re.search(link_extension_regex, link_main)
+                        if link_extension:
+                            link_extension = link_extension.group(1)
+                        else:
+                            link_extension = 'jpg'
+
+                        link_main = re.sub(link_extension_regex, '', link_main)
+                        link_main_org = link_main
+
+                        link_main = '/image/' + url_pas(sha224_replace(link_main)) + '.' + link_extension
+
+                    file_end = '<image style="width:' + file_width + ';height:' + file_height + ';' + file_align + '" src="' + link_main + '">'
+                    if file_align == 'center':
+                        file_end = '<div style="text-align:center;">' + file_end + '</div>'
+
+                    if link_exist != '':
+                        data_name = self.get_tool_data_storage('<a class="' + link_exist + '" href="/upload?name=' + url_pas(link_main_org) + '">', '</a>', link_data_full)
+
+                        self.render_data = re.sub(link_regex, '<' + data_name + '>' + link_sub + '</' + data_name + '>', self.render_data, 1)
+                    else:
+                        data_name = self.get_tool_data_storage(file_end, '', link_data_full)
+
+                        self.render_data = re.sub(link_regex, '<' + data_name + '></' + data_name + '>', self.render_data, 1)
+                # category
+                elif re.search(r'^(분류|category):', link_main):
+                    link_main = re.sub(r'^(분류|category):', '', link_main)
+
+                    if self.data_category == '':
+                        self.data_category = '<div class="opennamu_category">' + self.get_tool_lang('category') + ' : '
+                    else:
+                        self.data_category += ' | '
+
+                    if link_data[1]:
+                        link_main += link_data[1]
+
+                    category_blur = ''
+                    if re.search(r'#blur$', link_main):
+                        link_main = re.sub(r'#blur$', '', link_main)
+
+                        category_blur = 'opennamu_category_blur'
+                    
+                    link_sub = link_main
+
+                    link_main = self.get_tool_data_restore(link_main, do_type = 'slash')
+                    link_main = html.unescape(link_main)
+
+                    self.curs.execute(db_change("select title from data where title = ?"), ['category:' + link_main])
+                    db_data = self.curs.fetchall()
+                    if db_data:
+                        link_exist = ''
+                    else:
+                        link_exist = 'opennamu_not_exist_link'
+
+                    link_main = url_pas(link_main)
+
+                    self.data_category += '<a class="' + category_blur + ' ' + link_exist + '" href="/w/category:' + link_main + '">' + link_sub + '</a>'
+
+                    self.render_data = re.sub(link_regex, '', self.render_data, 1)
+                # out link
+                elif re.search(r'^https?:\/\/', link_main):
+                    link_main = self.get_tool_data_restore(link_main, do_type = 'slash')
+                    link_main = html.unescape(link_main)
+                    link_main = re.sub(r'"', '&quot;', link_main)
+                    
+                    # sub not exist -> sub = main
+                    if link_data[1]:
+                        link_sub = link_data[1]
+                        link_sub_storage = ''
+                    else:
+                        link_sub = ''
+                        link_sub_storage = link_main_org
+
+                    data_name = self.get_tool_data_storage('<a class="opennamu_link_out" href="' + link_main + '">' + link_sub_storage, '</a>', link_data_full)
+
+                    self.render_data = re.sub(link_regex, '<' + data_name + '>' + link_sub + '</' + data_name + '>', self.render_data, 1)
+                # in link
+                else:
+                    # sharp
+                    link_data_sharp_regex = r'#([^#]+)$'
+                    link_data_sharp = re.search(link_data_sharp_regex, link_main)
+                    if link_data_sharp:
+                        link_data_sharp = link_data_sharp.group(1)
+                        link_data_sharp = html.unescape(link_data_sharp)
+                        link_data_sharp = '#' + url_pas(link_data_sharp)
+
+                        link_main = re.sub(link_data_sharp_regex, '', link_main)
+                    else:
+                        link_data_sharp = ''
+
+                    # under page & fix url
+                    if link_main == '../':
+                        link_main = self.doc_name
+                        link_main = re.sub(r'(\/[^/]+)$', '', link_main)
+                    elif re.search(r'^\/', link_main):
+                        link_main = re.sub(r'^\/', self.doc_name + '/', link_main)
+                    elif re.search(r'^분류:', link_main):
+                        link_main = re.sub(r'^분류:', 'category:', link_main)
+                    elif re.search(r'^사용자:', link_main):
+                        link_main = re.sub(r'^사용자:', 'user:', link_main)
+
+                    # main link fix
+                    link_main = self.get_tool_data_restore(link_main, do_type = 'slash')
+                    link_main = html.unescape(link_main)
+
+                    self.curs.execute(db_change("select title from data where title = ?"), [link_main])
+                    db_data = self.curs.fetchall()
+                    if db_data:
+                        link_exist = ''
+                    else:
+                        link_exist = 'opennamu_not_exist_link'
+
+                    link_same = ''
+                    if link_main == self.doc_name and self.doc_include == '':
+                        link_same = 'opennamu_same_link'
+
+                    link_main = url_pas(link_main)
+
+                    if link_main != '':
+                        link_main = '/w/' + link_main
+
+                    # sub not exist -> sub = main
+                    if link_data[1]:
+                        link_sub = link_data[1]
+                        link_sub_storage = ''
+                    else:
+                        link_sub = ''
+                        link_sub_storage = link_main_org
+
+                    data_name = self.get_tool_data_storage('<a class="' + link_exist + ' ' + link_same + '" href="' + link_main + link_data_sharp + '">' + link_sub_storage, '</a>', link_data_full)
+
+                    self.render_data = re.sub(link_regex, '<' + data_name + '>' + link_sub + '</' + data_name + '>', self.render_data, 1)
+
+            link_count_all -= 1
+
+    def do_render_slash(self):
+        # slash text -> <slash_n>
+        
+        def do_render_slash_sub(match):
+            if match.group(1) == '<':
+                return '<'
+            else:
+                data_name = self.get_tool_data_storage(match.group(1), do_type = 'slash')
+
+                return '<' + data_name + '>'
+
+        self.render_data = re.sub(r'\\(&lt;|&gt;|&#x27;|&quot;|&amp;|.)', do_render_slash_sub, self.render_data)
+
+    def do_render_include_default(self):
+        def do_render_include_default_sub(match):
+            match_org = match.group(0)
+            match = match.groups()
+
+            if len(match) < 3:
+                match = list(match) + ['']
+
+            if match[2] == '\\':
+                return match_org
+            else:
+                slash_add = ''
+                if match[0]:
+                    if len(match[0]) % 2 == 1:
+                        slash_add = '\\' * (len(match[0]) - 1)
+                    else:
+                        slash_add = match[0]
+
+                return slash_add + match[2]
+
+        self.render_data = re.sub(r'(\\+)?@([^@=]+)=((?:\\@|[^@])+)@', do_render_include_default_sub, self.render_data)
+        self.render_data = re.sub(r'(\\+)?@([^@=]+)@', do_render_include_default_sub, self.render_data)
+
+    def do_render_include(self):
+        def do_render_include_default_sub(match):
+            match_org = match.group(0)
+            match = match.groups()
+
+            if len(match) < 3:
+                match = list(match) + ['']
+
+            if match[2] == '\\':
+                return match_org
+            else:
+                slash_add = ''
+                if match[0]:
+                    if len(match[0]) % 2 == 1:
+                        slash_add = '\\' * (len(match[0]) - 1)
+                    else:
+                        slash_add = match[0]
+
+                if match[1] in include_change_list:
+                    return slash_add + include_change_list[match[1]]
+                else:
+                    return slash_add + match[2]
+
+        include_num = 0
+        include_regex = r'\[include\(((?:(?!\[include\(|\)\]|<\/div>).)+)\)\]'
+        include_count_max = len(re.findall(include_regex, self.render_data)) * 2
+        include_change_list = {}
+        while 1:
+            include_num += 1
+            include_change_list = {}
+
+            match = re.search(include_regex, self.render_data)
+            if include_count_max < 0:
+                break
+            elif not match:
+                break
+            else:
+                match_org = match.group(0)
+                match = match.groups()
+
+                macro_split_regex = r'(?:^|,) *([^,]+)'
+                macro_split_sub_regex = r'(^[^=]+) *= *([^=]+)'
+
+                include_name = ''
+
+                data = re.findall(macro_split_regex, match[0])
+                for for_a in data:
+                    data_sub = re.search(macro_split_sub_regex, for_a)
+                    if data_sub:
+                        data_sub = data_sub.groups()
+                        
+                        data_sub_name = data_sub[0]
+                        data_sub_data = self.get_tool_data_restore(data_sub[1], do_type = 'slash')
+
+                        include_change_list[data_sub_name] = data_sub_data
+                    else:
+                        include_name = for_a
+
+                include_name_org = include_name
+                
+                include_name = self.get_tool_data_restore(include_name, do_type = 'slash')
+                include_name = html.unescape(include_name)
+
+                # load include db data
+                self.curs.execute(db_change("select data from data where title = ?"), [include_name])
+                db_data = self.curs.fetchall()
+                if db_data:
+                    # include link func
+                    include_link = ''
+                    if flask.request.cookies.get('main_css_include_link', '') == '1':
+                        include_link = '<div><a href="/w/' + url_pas(include_name) + '">(' + include_name_org + ')</a></div>'
+
+                    include_data = db_data[0][0]
+
+                    # parameter replace
+                    include_data = re.sub(r'(\\+)?@([^@=]+)=((?:\\@|[^@])+)@', do_render_include_default_sub, include_data)
+                    include_data = re.sub(r'(\\+)?@([^@=]+)@', do_render_include_default_sub, include_data)
+
+                    # remove include
+                    include_data = re.sub(include_regex, '', include_data)
+
+                    self.data_include += [['opennamu_include_' + str(include_num), include_name, include_data]]
+
+                    data_name = self.get_tool_data_storage('' + \
+                        include_link + \
+                        '<div id="opennamu_include_' + str(include_num) + '"></div>' + \
+                    '', '', match_org)
+                else:
+                    include_link = '<div><a class="opennamu_not_exist_link" href="/w/' + url_pas(include_name) + '">(' + include_name_org + ')</a></div>'
+
+                    data_name = self.get_tool_data_storage(include_link, '', match_org)
+
+                self.render_data = re.sub(include_regex, '<' + data_name + '></' + data_name + '>', self.render_data, 1)
+
+            include_count_max -= 1
+
+    def do_render_middle(self):
+        pass
+
+    def do_render_list(self):
+        pass
+
+    def do_render_table(self):
+        pass
+
+    def do_redner_footnote(self):
+        footnote_num = 0
+        footnote_regex = r'(?:\[\*((?:(?!\[\*|\]| ).)+)?(?: ((?:(?!\[\*|\]).)+))?\]|\[(각주|footnote)\])'
+        footnote_count_all = len(re.findall(footnote_regex, self.render_data)) * 4
+        while 1:
+            footnote_num += 1
+
+            footnote_data = re.search(footnote_regex, self.render_data)
+            if footnote_count_all < 0:
+                break
+            elif not footnote_data:
+                break
+            else:
+                footnote_data_org = footnote_data.group(0)
+                footnote_data = footnote_data.groups()
+                if footnote_data[2]:
+                    self.render_data = re.sub(footnote_regex, self.get_tool_footnote_make(), self.render_data, 1)
+                else:
+                    if not footnote_data[0]:
+                        footnote_name = str(footnote_num)
+                        footnote_name_add = ''
+                    else:
+                        footnote_name = footnote_data[0]
+                        footnote_name_add = ' (' + str(footnote_num) + ')'
+
+                    if not footnote_data[1]:
+                        footnote_text_data = ''
+                    else:
+                        footnote_text_data = footnote_data[1]
+
+                    if footnote_name in self.data_footnote:
+                        self.data_footnote[footnote_name]['list'] += [str(footnote_num)]
+                        footnote_first = self.data_footnote[footnote_name]['list'][0]
+                    
+                        data_name = self.get_tool_data_storage('<sup><a id="' + self.doc_include + 'rfn_' + str(footnote_num) + '" href="#' + self.doc_include + 'fn_' + footnote_first + '">(' + footnote_name + ' (' + str(footnote_num) + ')' + ')</a></sup>', '', footnote_data_org)
+
+                        self.render_data = re.sub(footnote_regex, '<' + data_name + '></' + data_name + '>', self.render_data, 1)
+                    else:
+                        self.data_footnote[footnote_name] = {}
+                        self.data_footnote[footnote_name]['list'] = [str(footnote_num)]
+                        self.data_footnote[footnote_name]['data'] = footnote_text_data
+
+                        data_name = self.get_tool_data_storage('<sup><a id="' + self.doc_include + 'rfn_' + str(footnote_num) + '" href="#' + self.doc_include + 'fn_' + str(footnote_num) + '">(' + footnote_name + footnote_name_add + ')</a></sup>', '', footnote_data_org)
+
+                        self.render_data = re.sub(footnote_regex, '<' + data_name + '></' + data_name + '>', self.render_data, 1)
+
+            footnote_count_all -= 1
+
+        self.render_data += '<footnote_category>'
+        self.render_data += self.get_tool_footnote_make()
+
+    def do_render_redirect(self):
+        match = re.search(r'^<back_br>\n#(?:redirect|넘겨주기) ([^\n]+)', self.render_data)
+        if match:
+            link_data_full = match.group(0)
+            link_main = match.group(1)
+
+            # sharp
+            link_data_sharp_regex = r'#([^#]+)$'
+            link_data_sharp = re.search(link_data_sharp_regex, link_main)
+            if link_data_sharp:
+                link_data_sharp = link_data_sharp.group(1)
+                link_data_sharp = html.unescape(link_data_sharp)
+                link_data_sharp = '#' + url_pas(link_data_sharp)
+
+                link_main = re.sub(link_data_sharp_regex, '', link_main)
+            else:
+                link_data_sharp = ''
+
+            # under page & fix url
+            if link_main == '../':
+                link_main = self.doc_name
+                link_main = re.sub(r'(\/[^/]+)$', '', link_main)
+            elif re.search(r'^\/', link_main):
+                link_main = re.sub(r'^\/', self.doc_name + '/', link_main)
+            elif re.search(r'^분류:', link_main):
+                link_main = re.sub(r'^분류:', 'category:', link_main)
+            elif re.search(r'^사용자:', link_main):
+                link_main = re.sub(r'^사용자:', 'user:', link_main)
+
+            link_main = self.get_tool_data_restore(link_main, do_type = 'slash')
+            link_main = html.unescape(link_main)
+            link_main = url_pas(link_main)
+
+            if link_main != '':
+                link_main = '/w_from/' + link_main
+
+            if 'doc_from' in self.doc_set:
+                data_name = self.get_tool_data_storage('<a href="' + link_main + link_data_sharp + '">(GO)</a>', link_data_full)
+            else:
+                data_name = self.get_tool_data_storage('<meta http-equiv="refresh" content="0; url=' + link_main + link_data_sharp + '">', link_data_full)
+                
+            self.render_data = '<' + data_name + '></' + data_name + '>'
 
     def do_render_last(self):
+        # add category
+        if self.doc_include == '':
+            if self.data_category != '':
+                data_name = self.get_tool_data_storage(self.data_category, '</div>', '')
+
+                if flask.request.cookies.get('main_css_category_set', '') == '':
+                    if re.search(r'<footnote_category>', self.render_data):
+                        self.render_data = re.sub(r'<footnote_category>', '<' + data_name + '></' + data_name + '>', self.render_data, 1)
+                    else:
+                        self.render_data += '<' + data_name + '></' + data_name + '>'
+                else:
+                    self.render_data = re.sub(r'<footnote_category>', '', self.render_data, 1)
+                    self.render_data = '<' + data_name + '></' + data_name + '>' + self.render_data
+            else:
+                self.render_data = re.sub(r'<footnote_category>', '', self.render_data, 1)
+        else:
+            self.render_data = re.sub(r'<footnote_category>', '', self.render_data, 1)
+
         # remove front_br and back_br
-        self.render_data = re.sub(
-            r'\n<front_br>',
-            '',
-            self.render_data
-        )
-        self.render_data = re.sub(
-            r'<back_br>\n',
-            '',
-            self.render_data
-        )
+        self.render_data = re.sub(r'\n?<front_br>', '', self.render_data)
+        self.render_data = re.sub(r'<back_br>\n?', '', self.render_data)
         
         # \n to <br>
-        self.render_data = re.sub(
-            r'\n',
-            '<br>',
-            self.render_data
-        )
+        self.render_data = re.sub(r'\n', '<br>', self.render_data)
 
-    def __call__(self):
-        self.render_data = html.escape(self.doc_data)
-        
-        self.render_data_js = ''
+        # <render_n> restore
+        self.render_data = self.get_tool_data_restore(self.render_data)
+
+        self.render_data = '<div class="opennamu_render_complete">' + self.render_data + '</div>'
 
+    def __call__(self):
+        self.do_render_include_default()
+        self.do_render_slash()
+        self.do_render_redirect()
+        self.do_render_include()
+        self.do_render_math()
+        # self.do_render_middle()
+        # self.do_render_list()
+        # self.do_render_table()
+        self.do_render_link()
+        self.do_redner_footnote()
+        self.do_render_macro()
         self.do_render_text()
+        self.do_render_heading()
         self.do_render_last()
-        
+
+        # print(self.data_temp_storage)
+        # print(self.render_data)
+
         return [
-            self.render_data, # HTML
-            self.render_data_js, # JS
-            [] # Other
+            self.render_data, # html
+            self.render_data_js, # js
+            {
+                'backlink' : self.data_backlink, # backlink
+                'include' : self.data_include # include data
+            } # other
         ]

+ 71 - 31
route/topic.py

@@ -9,6 +9,12 @@ def topic(topic_num = 0):
             name = flask.request.form.get('topic', 'Test')
             sub = flask.request.form.get('title', 'Test')
             
+            if do_title_length_check(name) == 1:
+                return re_error('/error/38')
+            
+            if do_title_length_check(sub, 'topic') == 1:
+                return re_error('/error/38')
+            
             if topic_num == '0':
                 curs.execute(db_change("select code from topic order by code + 0 desc limit 1"))
                 t_data = curs.fetchall()
@@ -26,7 +32,10 @@ def topic(topic_num = 0):
                 else:
                     return redirect('/')
 
-        ban = acl_check(name, 'topic', topic_num)
+        topic_acl = acl_check('', 'topic', topic_num)
+        topic_view_acl = acl_check('', 'topic_view', topic_num)
+        if topic_view_acl == 1:
+            return re_error('/ban')
 
         if flask.request.method == 'POST':
             if flask.request.form.get('content', 'Test') == '':
@@ -40,7 +49,7 @@ def topic(topic_num = 0):
             ip = ip_check()
             today = get_time()
 
-            if ban == 1:
+            if topic_acl == 1:
                 return re_error('/ban')
 
             curs.execute(db_change("select id from topic where code = ? order by id + 0 desc limit 1"), [topic_num])
@@ -68,43 +77,73 @@ def topic(topic_num = 0):
                         y_check = 1
 
                 if y_check == 1:
-                    add_alarm(match, ip + ' | <a href="/thread/' + topic_num + '#' + num + '">' + name + ' | ' + sub + ' | #' + num + '</a>')
+                    add_alarm(match, ip + ' | <a href="/thread/' + topic_num + '#' + num + '">' + html.escape(name) + ' | ' + html.escape(sub) + ' | #' + num + '</a>')
 
             cate_re = re.compile(r'\[\[((?:분류|category):(?:(?:(?!\]\]).)*))\]\]', re.I)
             data = cate_re.sub('[br]', flask.request.form.get('content', 'Test').replace('\r', ''))
 
-            for rd_data in re.findall(r"(?: |\n|^)(#(?:[0-9]+))(?: |\n|$)", data):
-                curs.execute(db_change("select ip from topic where code = ? and id = ?"), [topic_num, rd_data])
-                ip_data = curs.fetchall()
-                if ip_data and ip_or_user(ip_data[0][0]) == 0:
-                    add_alarm(ip_data[0][0], ip + ' | <a href="/thread/' + topic_num + '#' + num + '">' + name + ' | ' + sub + ' | #' + num + '</a>')
-
-            for rd_data in re.findall(r"(?: |\n|^)@((?:[^ ]+))(?: |\n|$)", data):
-                curs.execute(db_change("select ip from history where ip = ? limit 1"), [rd_data])
-                ip_data = curs.fetchall()
-                if not ip_data:
-                    curs.execute(db_change("select ip from topic where ip = ? limit 1"), [rd_data])
+            call_thread_regex = r"( |\n|^)(?:#([0-9]+))( |\n|$)"
+            call_thread_count = len(re.findall(call_thread_regex, data)) * 3
+            while 1:
+                rd_data = re.search(call_thread_regex, data)
+                if call_thread_count < 0:
+                    break
+                elif not rd_data:
+                    break
+                else:
+                    rd_data = rd_data.groups()
+
+                    curs.execute(db_change("select ip from topic where code = ? and id = ?"), [topic_num, rd_data[1]])
+                    ip_data = curs.fetchall()
+                    if ip_data and ip_or_user(ip_data[0][0]) == 0 and ip != ip_data[0][0]:
+                        add_alarm(ip_data[0][0], ip + ' | <a href="/thread/' + topic_num + '#' + num + '">' + html.escape(name) + ' | ' + html.escape(sub) + ' | #' + num + '</a>')
+
+                    data = re.sub(call_thread_regex, rd_data[0] + '<topic_a>#' + rd_data[1] + '</topic_a>' + rd_data[2], data, 1)
+
+                call_thread_count -= 1
+
+            call_user_regex = r"( |\n|^)(?:@([^ ]+))( |\n|$)"
+            call_user_count = len(re.findall(call_user_regex, data)) * 3
+            while 1:
+                rd_data = re.search(call_user_regex, data)
+                if call_user_count < 0:
+                    break
+                elif not rd_data:
+                    break
+                else:
+                    rd_data = rd_data.groups()
+
+                    curs.execute(db_change("select ip from history where ip = ? limit 1"), [rd_data[1]])
                     ip_data = curs.fetchall()
+                    if not ip_data:
+                        curs.execute(db_change("select ip from topic where ip = ? limit 1"), [rd_data[1]])
+                        ip_data = curs.fetchall()
+
+                    if ip_data and ip_or_user(ip_data[0][0]) == 0 and ip != ip_data[0][0]:
+                        add_alarm(ip_data[0][0], ip + ' | <a href="/thread/' + topic_num + '#' + num + '">' + html.escape(name) + ' | ' + html.escape(sub) + ' | #' + num + '</a>')
 
-                if ip_data and ip_or_user(ip_data[0][0]) == 0:
-                    add_alarm(ip_data[0][0], ip + ' | <a href="/thread/' + topic_num + '#' + num + '">' + name + ' | ' + sub + ' | #' + num + '</a>')
+                    data = re.sub(call_user_regex, rd_data[0] + '<topic_call>@' + rd_data[1] + '</topic_call>' + rd_data[2], data, 1)
 
-            data = re.sub(r"( |\n|^)(#(?:[0-9]+))( |\n|$)", '\g<1><topic_a>\g<2></topic_a>\g<3>', data)
-            data = re.sub(r"( |\n|^)(@(?:[^ ]+))( |\n|$)", '\g<1><topic_call>\g<2></topic_call>\g<3>', data)
+                call_user_count -= 1
 
-            rd_plus(topic_num, today, name, sub)
-            curs.execute(db_change("insert into topic (id, data, date, ip, code) values (?, ?, ?, ?, ?)"), [
-                num,
+            do_add_thread(
+            	topic_num,
                 data,
-                today,
-                ip,
-                topic_num
-            ])
+                '',
+                num
+            )
+            do_reload_recent_thread(
+                topic_num, 
+                today, 
+                name, 
+                sub
+            )
+
             conn.commit()
 
             return redirect('/thread/' + topic_num + '#' + num)
         else:
-            display = 'display: none;' if ban == 1 else ''
+            display = 'display: none;' if topic_acl == 1 else ''
             data_input_topic_name = ''
             if topic_num == '0':
                 data_input_topic_name = '' + \
@@ -125,21 +164,22 @@ def topic(topic_num = 0):
                     <div id="top_topic"></div>
                     <div id="main_topic"></div>
                     <div id="plus_topic"></div>
-                    <script>opennamu_do_thread_make("''' + topic_num + '''");</script>
                     <a href="/thread/''' + topic_num + '/tool">(' + load_lang('topic_tool') + ''')</a>
                     <hr class="main_hr">
                     <form style="''' + display + '''" method="post">
                         ''' + data_input_topic_name + '''
-                        <textarea id="textarea_edit_view" class="opennamu_comment_textarea" placeholder="''' + topic_text + '''" name="content"></textarea>
+                        <textarea id="opennamu_js_edit_textarea" class="opennamu_comment_textarea" placeholder="''' + topic_text + '''" name="content"></textarea>
                         <hr class="main_hr">
                         ''' + captcha_get() + (ip_warning() if display == '' else '') + '''
                         <input style="display: none;" name="topic" value="''' + name + '''">
                         <input style="display: none;" name="title" value="''' + sub + '''">
-                        <button id="save" type="submit">''' + load_lang('send') + '''</button>
-                        <button id="preview" type="button" onclick="load_preview(\'\')">''' + load_lang('preview') + '''</button>
+                        <button id="opennamu_js_save" type="submit">''' + load_lang('send') + '''</button>
+                        <button id="opennamu_js_preview" type="button">''' + load_lang('preview') + '''</button>
                     </form>
                     <hr class="main_hr">
-                    <div id="see_preview"></div>
+                    <div id="opennamu_js_preview_area"></div>
+                    <!-- JS : opennamu_do_thread_make -->
+                    <!-- JS : edit.js -->
                 ''',
                 menu = [['topic/' + url_pas(name), load_lang('list')]]
             ))

+ 6 - 3
route/topic_comment_blind.py

@@ -3,10 +3,10 @@ from .tool.func import *
 def topic_comment_blind(topic_num = 1, num = 1):
     with get_db_connect() as conn:
         curs = conn.cursor()
-
+        
         topic_num = str(topic_num)
         num = str(num)
-
+        
         if admin_check(3, 'blind (code ' + topic_num + '#' + num + ')') != 1:
             return re_error('/error/3')
 
@@ -18,7 +18,10 @@ def topic_comment_blind(topic_num = 1, num = 1):
             else:
                 curs.execute(db_change("update topic set block = 'O' where code = ? and id = ?"), [topic_num, num])
 
-            rd_plus(topic_num, get_time())
+            do_reload_recent_thread(
+                topic_num, 
+                get_time()
+            )
 
             conn.commit()
 

+ 7 - 3
route/topic_comment_notice.py

@@ -3,10 +3,10 @@ from .tool.func import *
 def topic_comment_notice(topic_num = 1, num = 1):
     with get_db_connect() as conn:
         curs = conn.cursor()
-
+        
         topic_num = str(topic_num)
         num = str(num)
-
+        
         if admin_check(3, 'notice (code ' + topic_num + '#' + num + ')') != 1:
             return re_error('/error/3')
 
@@ -20,7 +20,11 @@ def topic_comment_notice(topic_num = 1, num = 1):
                 else:
                     curs.execute(db_change("update topic set top = 'O' where code = ? and id = ?"), [topic_num, num])
 
-            rd_plus(topic_num, get_time())
+            do_reload_recent_thread(
+                topic_num, 
+                get_time()
+            )
+            
             conn.commit()
 
         return redirect('/thread/' + topic_num + '#' + num)

+ 5 - 2
route/topic_comment_tool.py

@@ -3,9 +3,12 @@ from .tool.func import *
 def topic_comment_tool(topic_num = 1, num = 1):
     with get_db_connect() as conn:
         curs = conn.cursor()
-
+        
         num = str(num)
         topic_num = str(topic_num)
+        
+        if acl_check('', 'topic_view', topic_num) == 1:
+            return re_error('/ban')
 
         curs.execute(db_change("select block, ip, date from topic where code = ? and id = ?"), [topic_num, num])
         data = curs.fetchall()
@@ -41,7 +44,7 @@ def topic_comment_tool(topic_num = 1, num = 1):
                 <h2>''' + load_lang('admin_tool') + '''</h2>
                 <ul class="inside_ul">
                     <li>
-                        <a href="/ban/''' + url_pas(data[0][1]) + '''">
+                        <a href="/auth/give/ban/''' + url_pas(data[0][1]) + '''">
                             ''' + (load_lang('release') if user_ban_d else load_lang('ban')) + '''
                         </a>
                     </li>

+ 4 - 9
route/topic_list.py

@@ -36,15 +36,10 @@ def topic_list(name = 'Test'):
             t_data = curs.fetchall()
 
             div += '''
-                <h2><a href="/thread/''' + data[0] + '">' + html.escape(data[0] + '. ' + data[1]) + '''</a></h2>
-                <div id="topic_pre_''' + data[0] + '''"></div>
-                <div id="topic_back_pre_''' + data[0] + '''"></div>
-                <script>
-                    opennamu_do_thread_make(''' + data[0] + ', "list", "/normal/1", "topic_pre_' + data[0] + '''");
-                    if(''' + t_data[0][0] + ''' !== 1) {
-                        opennamu_do_thread_make(''' + data[0] + ', "list", "/normal/' + t_data[0][0] + '", "topic_back_pre_' + data[0] + '''");
-                    }
-                </script>
+                <h2><a href="/thread/''' + data[0] + '">' + data[0] + '. ' + html.escape(data[1]) + '''</a></h2>
+                <div class="topic_pre" id="opennamu_thread_''' + data[0] + '''"></div>
+                <div class="topic_back_pre" id="opennamu_thread_back_''' + data[0] + '''"></div>
+                <!-- JS : opennamu_do_thread_make -->
             '''
 
         if div == '':

+ 28 - 7
route/topic_tool.py

@@ -11,16 +11,36 @@ def topic_tool(topic_num = 1):
         close_data = curs.fetchall()
         if close_data:
             if close_data[0][0] == 'S':
-                t_state = 'Stop'
+                t_state = load_lang('topic_stop')
             elif close_data[0][0] == 'O':
-                t_state = 'Close'
+                t_state = load_lang('topic_close')
             else:
-                t_state = 'Normal'
+                t_state = load_lang('topic_normal')
+                
+            if close_data[0][1] == 'O':
+                t_state += ' (' + load_lang('topic_agree') + ')'
         else:
-            t_state = 'Normal'
+            t_state = load_lang('topic_normal')
 
         curs.execute(db_change("select acl from rd where code = ?"), [topic_num])
-        topic_acl_get = curs.fetchall()
+        db_data = curs.fetchall()
+        if db_data:
+            if db_data[0][0] == '':
+                acl_state = 'normal'
+            else:
+                acl_state = db_data[0][0]
+        else:
+            acl_state = 'normal'
+        
+        curs.execute(db_change("select set_data from topic_set where thread_code = ? and set_name = 'thread_view_acl'"), [topic_num])
+        db_data = curs.fetchall()
+        if db_data:
+            if db_data[0][0] == '':
+                acl_view_state = 'normal'
+            else:
+                acl_view_state = db_data[0][0]
+        else:
+            acl_view_state = 'normal'
 
         if admin_check(3) == 1:
             data = '''
@@ -33,8 +53,9 @@ def topic_tool(topic_num = 1):
         data += '''
             <h2>''' + load_lang('tool') + '''</h2>
             <ul class="inside_ul">
-                <li>''' + load_lang('topic_state') + ''' : ''' + t_state + '' + (' (Agree)' if close_data and (close_data[0][1] == 'O') else '') + '''</li>
-                <li>''' + load_lang('topic_acl') + ''' : <a href="/acl/TEST#exp">''' + ('Normal' if not topic_acl_get or (topic_acl_get[0][0] == '') else topic_acl_get[0][0]) + '''</a></li>
+                <li>''' + load_lang('topic_state') + ''' : ''' + t_state + '''</li>
+                <li>''' + load_lang('topic_acl') + ''' : <a href="/acl/TEST#exp">''' + acl_state + '''</a></li>
+                <li>''' + load_lang('topic_view_acl') + ''' : <a href="/acl/TEST#exp">''' + acl_view_state + '''</a></li>
             </ul>
         '''
 

+ 42 - 13
route/topic_tool_acl.py

@@ -23,26 +23,41 @@ def topic_tool_acl(topic_num = 1):
             topic_check = curs.fetchall()
             if topic_check:
                 acl_data = flask.request.form.get('acl', '')
+                acl_data_view = flask.request.form.get('acl_view', '')
 
                 curs.execute(db_change("update rd set acl = ? where code = ?"), [
-                    acl_data,
-                    topic_num
-                ])
-
-                curs.execute(db_change("insert into topic (id, data, date, ip, top, code) values (?, ?, ?, ?, '1', ?)"), [
-                    str(int(topic_check[0][0]) + 1),
-                    'acl change ' + acl_data,
-                    time,
-                    ip,
+                    acl_data, 
                     topic_num
                 ])
+                
+                curs.execute(db_change("select set_data from topic_set where thread_code = ? and set_name = 'thread_view_acl'"), [topic_num])
+                db_data = curs.fetchall()
+                if db_data:
+                    curs.execute(db_change("update topic_set set set_data = ? where thread_code = ?"), [
+                        acl_data_view,
+                        topic_num
+                    ])
+                else:
+                    curs.execute(db_change("insert into topic_set (thread_code, set_name, set_id, set_data) values (?, 'thread_view_acl', '1', ?)"), [
+                        topic_num,
+                        acl_data_view
+                    ])
 
-                rd_plus(topic_num, time)
+                do_add_thread(
+                    topic_num,
+                	'acl change ' + acl_data,
+                    '1'
+                )
+                do_reload_recent_thread(
+                    topic_num, 
+                    time
+                )
 
             return redirect('/thread/' + topic_num)
         else:
             acl_list = get_acl_list()
             acl_html_list = ''
+            acl_html_list_view = ''
 
             curs.execute(db_change("select acl from rd where code = ?"), [topic_num])
             topic_acl_get = curs.fetchall()
@@ -54,16 +69,30 @@ def topic_tool_acl(topic_num = 1):
 
                 acl_html_list += '<option value="' + data_list + '" ' + check + '>' + (data_list if data_list != '' else 'normal') + '</option>'
 
+            curs.execute(db_change("select set_data from topic_set where thread_code = ? and set_name = 'thread_view_acl'"), [topic_num])
+            db_data = curs.fetchall()
+            for data_list in acl_list:
+                if db_data and db_data[0][0] == data_list:
+                    check = 'selected="selected"'
+                else:
+                    check = ''
+
+                acl_html_list_view += '<option value="' + data_list + '" ' + check + '>' + (data_list if data_list != '' else 'normal') + '</option>'
+
             return easy_minify(flask.render_template(skin_check(),
                 imp = [load_lang('topic_acl_setting'), wiki_set(), wiki_custom(), wiki_css([0, 0])],
                 data = '''
                     <form method="post">
                         <a href="/acl/TEST#exp">(''' + load_lang('reference') + ''')</a>
-                        <hr>
+                        <h2>''' + load_lang('thread_acl') + '''</h2>
                         <select name="acl">
-                        ''' + acl_html_list + '''
+                            ''' + acl_html_list + '''
+                        </select>
+                        <h2>''' + load_lang('view_acl') + ''' (''' + load_lang('beta') + ''')</h2>
+                        <select name="acl_view">
+                            ''' + acl_html_list_view + '''
                         </select>
-                        <hr class=\"main_hr\">
+                        <hr class="main_hr">
                         <button type="submit">''' + load_lang('save') + '''</button>
                     </form>
                 ''',

+ 9 - 9
route/topic_tool_change.py

@@ -31,15 +31,15 @@ def topic_tool_change(topic_num = 1):
                     topic_num
                 ])
 
-                curs.execute(db_change("insert into topic (id, data, date, ip, top, code) values (?, ?, ?, ?, '1', ?)"), [
-                    str(int(topic_check[0][0]) + 1),
-                    'change name to ' + sub_d + '(' + title_d + ')',
-                    time,
-                    ip,
-                    topic_num
-                ])
-
-                rd_plus(topic_num, time)
+                do_add_thread(
+                    topic_num,
+                    'change name to ' + sub_d + ' (' + title_d + ')',
+                    '1'
+                )
+                do_reload_recent_thread(
+                    topic_num, 
+                    time
+                )
 
             return redirect('/thread/' + topic_num)
         else:

+ 55 - 25
route/topic_tool_setting.py

@@ -19,44 +19,66 @@ def topic_tool_setting(topic_num = 1):
         if flask.request.method == 'POST':
             admin_check(3, 'change_topic_set (code ' + topic_num + ')')
 
-            curs.execute(db_change("select id from topic where code = ? order by id + 0 desc limit 1"), [topic_num])
-            topic_check = curs.fetchall()
-            if topic_check:
-                stop_d = flask.request.form.get('stop_d', '')
-                why_d = flask.request.form.get('why', '')
-                agree_d = flask.request.form.get('agree', '')
-
-                curs.execute(db_change("update rd set stop = ?, agree = ? where code = ?"), [
+            stop_d = flask.request.form.get('stop_d', '')
+            why_d = flask.request.form.get('why', '')
+            agree_d = flask.request.form.get('agree', '')
+
+            if stop_d != rd_d[0][0]:
+                curs.execute(db_change("update rd set stop = ? where code = ?"), [
                     stop_d,
-                    agree_d,
                     topic_num
                 ])
 
                 if stop_d == 'S':
-                    t_state = 'Stop'
+                    t_state = 'topic_state_change_stop'
                 elif stop_d == 'O':
-                    t_state = 'Close'
+                    t_state = 'topic_state_change_close'
                 else:
-                    t_state = 'Normal'
+                    t_state = 'topic_state_change_normal'
+
+                do_add_thread(
+                    topic_num,
+                    load_lang(t_state),
+                    '1'
+                )
 
-                curs.execute(db_change("insert into topic (id, data, date, ip, top, code) values (?, ?, ?, ?, '1', ?)"), [
-                    str(int(topic_check[0][0]) + 1),
-                    t_state + (' (Agree)' if agree_d != '' else '') + (('[br][br]Why : ' + why_d) if why_d else ''),
-                    time,
-                    ip,
+            if agree_d != rd_d[0][1]:
+                curs.execute(db_change("update rd set agree = ? where code = ?"), [
+                    agree_d,
                     topic_num
                 ])
 
-                rd_plus(topic_num, time)
+                if agree_d == 'O':
+                    t_state = 'topic_state_change_agree'
+                else:
+                    t_state = 'topic_state_change_disagree'
+
+                do_add_thread(
+                    topic_num,
+                    load_lang(t_state),
+                    '1'
+                )
+
+            if why_d != '':
+                do_add_thread(
+                    topic_num,
+                    load_lang('why') + ' : ' + why_d,
+                    '1'
+                )
+            
+            do_reload_recent_thread(
+                topic_num, 
+                time
+            )
 
             return redirect('/thread/' + topic_num)
         else:
             stop_d_list = ''
             agree_check = ''
             for_list = [
-                ['O', 'Close'],
-                ['S', 'Stop'],
-                ['', 'Normal']
+                ['O', load_lang('topic_close')],
+                ['S', load_lang('topic_stop')],
+                ['', load_lang('topic_normal')]
             ]
 
             for i in for_list:
@@ -71,14 +93,22 @@ def topic_tool_setting(topic_num = 1):
                 imp = [load_lang('topic_setting'), wiki_set(), wiki_custom(), wiki_css([0, 0])],
                 data = '''
                     <form method="post">
+                        <h2>1. ''' + load_lang('topic_progress') + '''</h2>
                         <select name="stop_d">
                             ''' + stop_d_list + '''
                         </select>
-                        <hr class=\"main_hr\">
-                        <input type="checkbox" name="agree" value="O" ''' + agree_check + '''> Agree
-                        <hr class=\"main_hr\">
+                        <hr class="main_hr">
+                        <input type="checkbox" name="agree" value="O" ''' + agree_check + '''> ''' + load_lang('topic_change_agree') + '''
+
+                        <h2>2. ''' + load_lang('topic_associate') + '''</h2>
+                        ''' + load_lang('topic_link_vote') + ''' (''' + load_lang('not_working') + ''')
+                        <hr class="main_hr">
+                        <input placeholder="''' + load_lang('topic_insert_vote_number') + '''" name="vote_number" type="number">
+
+                        <h2>3. ''' + load_lang('why') + '''</h2>
                         <input placeholder="''' + load_lang('why') + ''' (''' + load_lang('markup_enabled') + ''')" name="why" type="text">
-                        <hr class=\"main_hr\">
+                        <hr class="main_hr">
+
                         <button type="submit">''' + load_lang('save') + '''</button>
                     </form>
                 ''',

+ 1 - 7
route/user_alarm.py

@@ -19,16 +19,10 @@ def user_alarm():
             ''
     
             for data_one in data_list:
-                data += '' + \
-                    '<li>' + \
-                        '<span class="send_content">' + html.escape(data_one[0]) + '</span> ' + \
-                        '(' + data_one[1] + ')' + \
-                    '</li>' + \
-                ''
+                data += '<li>' + data_one[0] + ' (' + data_one[1] + ')</li>'
     
         data += '' + \
             '</ul>' + \
-            '<script>send_render();</script>' + \
             next_fix('/alarm?num=', num, data_list) + \
         ''
     

+ 5 - 5
route/user_challenge.py

@@ -22,13 +22,13 @@ def do_make_challenge_design(img, title, info, disable = 0):
         <hr class="main_hr">
     '''
 
-def user_challenge():
-    ip = ip_check()
-    if ip_or_user(ip) == 1:
-        return redirect('/user')
-    
+def user_challenge():    
     with get_db_connect() as conn:
         curs = conn.cursor()
+        
+        ip = ip_check()
+        if ip_or_user(ip) == 1:
+            return redirect('/user')
 
         data_html_green = ''
         data_html_red = ''

+ 47 - 3
route/user_count.py

@@ -19,16 +19,60 @@ def user_count(name = None):
         curs.execute(db_change("select count(*) from topic where ip = ?"), [that])
         count = curs.fetchall()
         if count:
-            t_data = count[0][0]
+            data_topic = count[0][0]
         else:
-            t_data = 0
+            data_topic = 0
+            
+        date = get_time()
+        date = date.split()
+        date = date[0]
+            
+        curs.execute(db_change("select count(*) from history where date like ? and ip = ?"), [date + '%', that])
+        count = curs.fetchall()
+        if count:
+            data_today = count[0][0]
+        else:
+            data_today = 0
+            
+        data_today_len = 0
+            
+        curs.execute(db_change("select leng from history where date like ? and ip = ?"), [date + '%', that])
+        db_data = curs.fetchall()
+        for count in db_data:
+        	data_today_len += int(count[0][1:])
+
+        date_yesterday = str((
+            datetime.datetime.today() + datetime.timedelta(days = -1)
+        ).strftime("%Y-%m-%d"))
+
+        curs.execute(db_change("select count(*) from history where date like ? and ip = ?"), [date_yesterday + '%', that])
+        count = curs.fetchall()
+        if count:
+            data_yesterday = count[0][0]
+        else:
+            data_yesterday = 0
+            
+        data_yesterday_len = 0
+            
+        curs.execute(db_change("select leng from history where date like ? and ip = ?"), [date_yesterday + '%', that])
+        db_data = curs.fetchall()
+        for count in db_data:
+        	data_yesterday_len += int(count[0][1:])
 
+        # 한글 지원 필요
         return easy_minify(flask.render_template(skin_check(),
             imp = [load_lang('count'), wiki_set(), wiki_custom(), wiki_css([0, 0])],
             data = '''
                 <ul class="inside_ul">
                     <li><a href="/record/''' + url_pas(that) + '''">''' + load_lang('edit_record') + '''</a> : ''' + str(data) + '''</li>
-                    <li><a href="/record/topic/''' + url_pas(that) + '''">''' + load_lang('discussion_record') + '''</a> : ''' + str(t_data) + '''</a></li>
+                    <li><a href="/record/topic/''' + url_pas(that) + '''">''' + load_lang('discussion_record') + '''</a> : ''' + str(data_topic) + '''</a></li>
+                    <hr>
+                    <li>(''' + load_lang('beta') + ''') TODAY : ''' + str(data_today) + '''</li>
+                    <li>(''' + load_lang('beta') + ''') TODAY LEN : ''' + str(data_today_len) + '''</li>
+                    <li>(''' + load_lang('beta') + ''') TODAY DIFF : ''' + str(data_today_len - data_yesterday_len) + '''</li>
+                    <hr>
+                    <li>(''' + load_lang('beta') + ''') YESTERDAY : ''' + str(data_yesterday) + '''</li>
+                    <li>(''' + load_lang('beta') + ''') YESTERDAY LEN : ''' + str(data_yesterday_len) + '''</li>
                 </ul>
             ''',
             menu = [['user', load_lang('return')]]

+ 2 - 3
route/user_info.py

@@ -50,7 +50,7 @@ def user_info(name = ''):
             admin_menu = '''
                 <h2>''' + load_lang('admin') + '''</h2>
                 <ul class="inside_ul">
-                    <li><a href="/ban/''' + url_pas(ip) + '''">''' + ban_name + '''</a></li>
+                    <li><a href="/auth/give/ban/''' + url_pas(ip) + '''">''' + ban_name + '''</a></li>
                     <li><a href="/check/''' + url_pas(ip) + '''">''' + load_lang('check') + '''</a></li>
                 </ul>
             '''
@@ -61,8 +61,7 @@ def user_info(name = ''):
             imp = [load_lang('user_tool'), wiki_set(), wiki_custom(), wiki_css([0, 0])],
             data = '''
                 <h2>''' + load_lang('state') + '''</h2>
-                <div id="get_user_info"></div>
-                <script>load_user_info("''' + ip + '''");</script>
+                <div id="opennamu_get_user_info">''' + ip + '''</div>
                 ''' + login_menu + '''
                 ''' + tool_menu + '''
                 <h2>''' + load_lang('other') + '''</h2>

+ 5 - 12
route/user_setting.py

@@ -100,8 +100,7 @@ def user_setting():
                     imp = [load_lang('user_setting'), wiki_set(), wiki_custom(), wiki_css([0, 0])],
                     data = '''
                         <form method="post">
-                            <div id="get_user_info"></div>
-                            <script>load_user_info("''' + ip + '''");</script>
+                            <div id="opennamu_get_user_info">''' + ip + '''</div>
                             <hr class="main_hr">
                             <a href="/change/pw">(''' + load_lang('password_change') + ''')</a>
                             <hr class="main_hr">
@@ -123,17 +122,12 @@ def user_setting():
                             <hr class="main_hr">
                             <select name="user_title">''' + div4 + '''</select>
                             <h2>''' + load_lang('2fa') + '''</h2>
-                            <select name="2fa"
-                                    id="twofa_check_input"
-                                    onchange="do_twofa_check(0);">''' + fa_data_select + '''</select>
-                            <div id="fa_plus_content">
-                                <hr class="main_hr">
-                                <input type="password" name="2fa_pw" placeholder="''' + fa_data_pw + '''">
-                            </div>
+                            <select name="2fa" id="twofa_check_input">''' + fa_data_select + '''</select>
+                            <hr class="main_hr">
+                            <input type="password" name="2fa_pw" placeholder="''' + fa_data_pw + '''">
                             <hr class="main_hr">
                             <button type="submit">''' + load_lang('save') + '''</button>
                             ''' + http_warning() + '''
-                            <script>do_twofa_check(1);</script>
                         </form>
                     ''',
                     menu = [['user', load_lang('return')]]
@@ -165,8 +159,7 @@ def user_setting():
                     imp = [load_lang('user_setting'), wiki_set(), wiki_custom(), wiki_css([0, 0])],
                     data = '''
                         <form method="post">
-                            <div id="get_user_info"></div>
-                            <script>load_user_info("''' + ip + '''");</script>
+                            <div id="opennamu_get_user_info">''' + ip + '''</div>
                             <hr class="main_hr">
                             <h2>''' + load_lang('main') + '''</h2>
                             <span>''' + load_lang('skin') + '''</span>

+ 60 - 59
route/user_setting_email.py

@@ -1,75 +1,76 @@
 from .tool.func import *
 
-def user_setting_email_2(conn):
-    curs = conn.cursor()
-    
-    ip = ip_check()
-    if ip_or_user(ip) != 0:
-        return redirect('/login')
-    
-    if flask.request.method == 'POST':
-        # c_key 같은 이름 대신 한 기능에 고유 명칭 부여 필요
-        re_set_list = ['c_key']
-        flask.session['c_key'] = load_random_key(32)
+def user_setting_email_2():
+    with get_db_connect() as conn:
+        curs = conn.cursor()
 
-        user_email = re.sub(r'\\', '', flask.request.form.get('email', ''))
-        email_data = re.search(r'@([^@]+)$', user_email)
-        if email_data:
-            curs.execute(db_change("select html from html_filter where html = ? and kind = 'email'"), [email_data.group(1)])
-            if not curs.fetchall():
+        ip = ip_check()
+        if ip_or_user(ip) != 0:
+            return redirect('/login')
+
+        if flask.request.method == 'POST':
+            # c_key 같은 이름 대신 한 기능에 고유 명칭 부여 필요
+            re_set_list = ['c_key']
+            flask.session['c_key'] = load_random_key(32)
+
+            user_email = re.sub(r'\\', '', flask.request.form.get('email', ''))
+            email_data = re.search(r'@([^@]+)$', user_email)
+            if email_data:
+                curs.execute(db_change("select html from html_filter where html = ? and kind = 'email'"), [email_data.group(1)])
+                if not curs.fetchall():
+                    for i in re_set_list:
+                        flask.session.pop(i, None)
+
+                    return redirect('/email_filter')
+            else:
                 for i in re_set_list:
                     flask.session.pop(i, None)
 
-                return redirect('/email_filter')
-        else:
-            for i in re_set_list:
-                flask.session.pop(i, None)
+                return re_error('/error/36')
 
-            return re_error('/error/36')
+            curs.execute(db_change('select data from other where name = "email_title"'))
+            sql_d = curs.fetchall()
+            t_text = html.escape(sql_d[0][0]) if sql_d and sql_d[0][0] != '' else (wiki_set()[0] + ' key')
 
-        curs.execute(db_change('select data from other where name = "email_title"'))
-        sql_d = curs.fetchall()
-        t_text = html.escape(sql_d[0][0]) if sql_d and sql_d[0][0] != '' else (wiki_set()[0] + ' key')
+            curs.execute(db_change('select data from other where name = "email_text"'))
+            sql_d = curs.fetchall()
+            if sql_d and sql_d[0][0] != '':
+                i_text = html.escape(sql_d[0][0]) + '\n\nKey : ' + flask.session['c_key']
+            else:
+                i_text = 'Key : ' + flask.session['c_key']
 
-        curs.execute(db_change('select data from other where name = "email_text"'))
-        sql_d = curs.fetchall()
-        if sql_d and sql_d[0][0] != '':
-            i_text = html.escape(sql_d[0][0]) + '\n\nKey : ' + flask.session['c_key']
-        else:
-            i_text = 'Key : ' + flask.session['c_key']
-        
-        curs.execute(db_change('select id from user_set where name = "email" and data = ?'), [user_email])
-        if curs.fetchall():
-            for i in re_set_list:
-                flask.session.pop(i, None)
+            curs.execute(db_change('select id from user_set where name = "email" and data = ?'), [user_email])
+            if curs.fetchall():
+                for i in re_set_list:
+                    flask.session.pop(i, None)
 
-            return re_error('/error/35')
+                return re_error('/error/35')
 
-        if send_email(user_email, t_text, i_text) == 0:
-            for i in re_set_list:
-                flask.session.pop(i, None)
+            if send_email(user_email, t_text, i_text) == 0:
+                for i in re_set_list:
+                    flask.session.pop(i, None)
 
-            return re_error('/error/18')
+                return re_error('/error/18')
 
-        flask.session['c_email'] = user_email
+            flask.session['c_email'] = user_email
 
-        return redirect('/change/email/check')
-    else:
-        curs.execute(db_change('select data from other where name = "email_insert_text"'))
-        sql_d = curs.fetchall()
-        b_text = (sql_d[0][0] + '<hr class="main_hr">') if sql_d and sql_d[0][0] != '' else ''
+            return redirect('/change/email/check')
+        else:
+            curs.execute(db_change('select data from other where name = "email_insert_text"'))
+            sql_d = curs.fetchall()
+            b_text = (sql_d[0][0] + '<hr class="main_hr">') if sql_d and sql_d[0][0] != '' else ''
 
-        return easy_minify(flask.render_template(skin_check(),
-            imp = [load_lang('email'), wiki_set(), wiki_custom(), wiki_css([0, 0])],
-            data = '''
-                <a href="/email_filter">(''' + load_lang('email_filter_list') + ''')</a>
-                <hr class="main_hr">
-                ''' + b_text + '''
-                <form method="post">
-                    <input placeholder="''' + load_lang('email') + '''" name="email" type="text">
+            return easy_minify(flask.render_template(skin_check(),
+                imp = [load_lang('email'), wiki_set(), wiki_custom(), wiki_css([0, 0])],
+                data = '''
+                    <a href="/email_filter">(''' + load_lang('email_filter_list') + ''')</a>
                     <hr class="main_hr">
-                    <button type="submit">''' + load_lang('save') + '''</button>
-                </form>
-            ''',
-            menu = [['user', load_lang('return')]]
-        ))
+                    ''' + b_text + '''
+                    <form method="post">
+                        <input placeholder="''' + load_lang('email') + '''" name="email" type="text">
+                        <hr class="main_hr">
+                        <button type="submit">''' + load_lang('save') + '''</button>
+                    </form>
+                ''',
+                menu = [['user', load_lang('return')]]
+            ))

+ 43 - 42
route/user_setting_email_check.py

@@ -1,45 +1,46 @@
 from .tool.func import *
 
-def user_setting_email_check_2(conn):
-    curs = conn.cursor()
-    
-    ip = ip_check()
-    if ip_or_user(ip) != 0:
-        return redirect('/login')
-
-    re_set_list = ['c_key', 'c_email']
-    if  not 'c_key' in flask.session or \
-        not 'c_email' in flask.session:
-        for i in re_set_list:
-            flask.session.pop(i, None)
-    
-    if  flask.request.method == 'POST':
+def user_setting_email_check_2():
+    with get_db_connect() as conn:
+        curs = conn.cursor()
+
         ip = ip_check()
-        input_key = flask.request.form.get('key', '')
-        user_agent = flask.request.headers.get('User-Agent', '')
-
-        if flask.session['c_key'] == input_key:
-            curs.execute(db_change('delete from user_set where name = "email" and id = ?'), [ip])
-            curs.execute(db_change('insert into user_set (name, id, data) values ("email", ?, ?)'), [ip, flask.session['c_email']])
-
-        for i in re_set_list:
-            flask.session.pop(i, None)
-
-        return redirect('/change')
-    else:
-        curs.execute(db_change('select data from other where name = "check_key_text"'))
-        sql_d = curs.fetchall()
-        b_text = (sql_d[0][0] + '<hr class="main_hr">') if sql_d and sql_d[0][0] != '' else ''
-
-        return easy_minify(flask.render_template(skin_check(),
-            imp = [load_lang('check_key'), wiki_set(), wiki_custom(), wiki_css([0, 0])],
-            data = '''
-                <form method="post">
-                    ''' + b_text + '''
-                    <input placeholder="''' + load_lang('key') + '''" name="key" type="text">
-                    <hr class="main_hr">
-                    <button type="submit">''' + load_lang('save') + '''</button>
-                </form>
-            ''',
-            menu = [['user', load_lang('return')]]
-        ))
+        if ip_or_user(ip) != 0:
+            return redirect('/login')
+
+        re_set_list = ['c_key', 'c_email']
+        if  not 'c_key' in flask.session or \
+            not 'c_email' in flask.session:
+            for i in re_set_list:
+                flask.session.pop(i, None)
+
+        if  flask.request.method == 'POST':
+            ip = ip_check()
+            input_key = flask.request.form.get('key', '')
+            user_agent = flask.request.headers.get('User-Agent', '')
+
+            if flask.session['c_key'] == input_key:
+                curs.execute(db_change('delete from user_set where name = "email" and id = ?'), [ip])
+                curs.execute(db_change('insert into user_set (name, id, data) values ("email", ?, ?)'), [ip, flask.session['c_email']])
+
+            for i in re_set_list:
+                flask.session.pop(i, None)
+
+            return redirect('/change')
+        else:
+            curs.execute(db_change('select data from other where name = "check_key_text"'))
+            sql_d = curs.fetchall()
+            b_text = (sql_d[0][0] + '<hr class="main_hr">') if sql_d and sql_d[0][0] != '' else ''
+
+            return easy_minify(flask.render_template(skin_check(),
+                imp = [load_lang('check_key'), wiki_set(), wiki_custom(), wiki_css([0, 0])],
+                data = '''
+                    <form method="post">
+                        ''' + b_text + '''
+                        <input placeholder="''' + load_lang('key') + '''" name="key" type="text">
+                        <hr class="main_hr">
+                        <button type="submit">''' + load_lang('save') + '''</button>
+                    </form>
+                ''',
+                menu = [['user', load_lang('return')]]
+            ))

+ 32 - 11
route/user_setting_head.py

@@ -1,30 +1,37 @@
 from .tool.func import *
 
-def user_setting_head():
+def user_setting_head(skin_name = ''):
     with get_db_connect() as conn:
         curs = conn.cursor()
 
         ip = ip_check()
+
+        skin_name_org = skin_name
+        if skin_name != '':
+            skin_name = '_' + skin_name
     
         if flask.request.method == 'POST':
             get_data = flask.request.form.get('content', '')
             if ip_or_user(ip) == 0:
-                curs.execute(db_change("select id from user_set where id = ? and name = 'custom_css'"), [ip])
+                curs.execute(db_change("select id from user_set where id = ? and name = ?"), [ip, 'custom_css' + skin_name])
                 if curs.fetchall():
-                    curs.execute(db_change("update user_set set data = ? where id = ? and name = 'custom_css'"), [get_data, ip])
+                    curs.execute(db_change("update user_set set data = ? where id = ? and name = ?"), [get_data, ip, 'custom_css' + skin_name])
                 else:
-                    curs.execute(db_change("insert into user_set (id, name, data) values (?, 'custom_css', ?)"), [ip, get_data])
+                    curs.execute(db_change("insert into user_set (id, name, data) values (?, ?, ?)"), [ip, 'custom_css' + skin_name, get_data])
 
                 conn.commit()
         
-            flask.session['head'] = get_data
+            flask.session['head' + skin_name] = get_data
 
-            return redirect('/change/head')
+            if skin_name_org != '':
+                return redirect('/change/head/' + skin_name_org)
+            else:
+                return redirect('/change/head')
         else:
             if ip_or_user(ip) == 0:
                 start = ''
 
-                curs.execute(db_change("select data from user_set where id = ? and name = 'custom_css'"), [ip])
+                curs.execute(db_change("select data from user_set where id = ? and name = ?"), [ip, 'custom_css' + skin_name])
                 head_data = curs.fetchall()
                 data = head_data[0][0] if head_data else ''
             else:
@@ -32,7 +39,7 @@ def user_setting_head():
                     '<span>' + load_lang('user_head_warning') + '</span>' + \
                     '<hr class="main_hr">' + \
                 ''
-                data = flask.session['head'] if 'head' in flask.session else ''
+                data = flask.session['head' + skin_name] if 'head' + skin_name in flask.session else ''
 
             start += '' + \
                 '<span>' + \
@@ -43,13 +50,27 @@ def user_setting_head():
                 '<hr class="main_hr">' + \
             ''
 
+            if skin_name == '':
+                sub_name = ''
+            else:
+                sub_name = ' (' + skin_name_org + ')'
+
+            start = '' + \
+                '<a href="/change/head">(' + load_lang('all') + ')</a> ' + \
+                ' '.join(['<a href="/change/head/' + url_pas(i) + '">(' + html.escape(i) + ')</a>' for i in load_skin('', 1)]) + \
+                '<hr class="main_hr">' + \
+                start + \
+            ''
+
             return easy_minify(flask.render_template(skin_check(),
-                imp = [load_lang(data = 'user_head', safe = 1), wiki_set(), wiki_custom(), wiki_css([0, 0])],
+                imp = [load_lang(data = 'user_head', safe = 1), wiki_set(), wiki_custom(), wiki_css(['(HTML)' + sub_name, 0])],
                 data = start + '''
                     <form method="post">
-                        <textarea rows="25" cols="100" name="content">''' + data + '''</textarea>
+                        <textarea rows="25" cols="100" name="content">''' + html.escape(data) + '''</textarea>
+                        <hr class="main_hr">
+                        ''' + load_lang('user_css_warning') + ''' : <a href="/change/head_reset">/change/head_reset</a>
                         <hr class="main_hr">
-                        <button id="save" type="submit">''' + load_lang('save') + '''</button>
+                        <button id="opennamu_js_save" type="submit">''' + load_lang('save') + '''</button>
                     </form>
                 ''',
                 menu = [['user', load_lang('return')]]

Niektóre pliki nie zostały wyświetlone z powodu dużej ilości zmienionych plików