Sfoglia il codice sorgente

Merge pull request #1987 from openNAMU/dev

모르겠다 일반 베타 보내보자
잉여개발기 2 anni fa
parent
commit
dbc25530ee

+ 5 - 6
app.py

@@ -176,8 +176,6 @@ with get_db_connect() as conn:
     sql_data = curs.fetchall()
     app.secret_key = sql_data[0][0]
 
-    print('----')
-
     # Init-DB_Data
     server_set = {}
     server_set_var = get_init_set_list()
@@ -216,13 +214,9 @@ with get_db_connect() as conn:
 
         server_set[i] = server_set_val
 
-    print('----')
-
     # 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', 
@@ -317,6 +311,9 @@ app.route('/filter/extension_filter/del/<everything:name>', defaults = { 'tool'
 app.route('/list/document/old')(list_old_page)
 app.route('/list/document/old/<int:num>')(list_old_page)
 
+app.route('/list/document/no_link')(list_no_link)
+app.route('/list/document/no_link/<int:num>')(list_no_link)
+
 app.route('/list/document/acl')(list_acl)
 app.route('/list/document/acl/<int:arg_num>')(list_acl)
 
@@ -403,7 +400,9 @@ app.route('/history_add/<everything:name>', methods = ['POST', 'GET'])(recent_hi
 
 # Func-view
 app.route('/xref/<everything:name>')(view_xref)
+app.route('/xref_page/<int:num>/<everything:name>')(view_xref)
 app.route('/xref_this/<everything:name>', defaults = { 'xref_type' : 2 })(view_xref)
+app.route('/xref_this_page/<int:num>/<everything:name>', defaults = { 'xref_type' : 2 })(view_xref)
 
 app.route('/raw/<everything:name>')(view_raw_2)
 app.route('/raw_acl/<everything:name>', defaults = { 'doc_acl' : 1 })(view_raw_2)

+ 1 - 29
emergency_tool.py

@@ -25,11 +25,9 @@ if data_db_load == 'Y':
     conn = load_db.__enter__()
     curs = conn.cursor()
 else:
-    print('----')
     print('You can use [9, 11, 19]')
 
 # Main
-print('----')
 print('1. Backlink reset')
 print('2. reCAPTCHA delete')
 print('3. Ban delete')
@@ -54,17 +52,13 @@ print('22. Delete body top')
 print('23. Delete body bottom')
 print('24. SQLite to MySQL')
 
-print('----')
 what_i_do = input('Select : ')
-
 if what_i_do == '1':
-    print('----')
     go_num = input('All delete (Y) [Y, N] : ')
     if not go_num == 'N':
         curs.execute(db_change("delete from back"))
         conn.commit()
 
-    print('----')
     try:
         go_num = int(input('Count (100) : '))
     except ValueError:
@@ -72,7 +66,6 @@ if what_i_do == '1':
 
     num = 0
 
-    print('----')
     print('Load...')
 
     curs.execute(
@@ -86,11 +79,9 @@ if what_i_do == '1':
     )
     title = curs.fetchall()
 
-    print('----')
     print('Rest : ' + str(len(title)))
     print('Start : ' + title[0][0])
     time.sleep(1)
-    print('----')
 
     for name in title:
         num += 1
@@ -108,7 +99,6 @@ elif what_i_do == '2':
     curs.execute(db_change("delete from other where name = 'recaptcha'"))
     curs.execute(db_change("delete from other where name = 'sec_re'"))
 elif what_i_do == '3':
-    print('----')
     user_data = input('IP or Name : ')
 
     curs.execute(
@@ -128,34 +118,27 @@ elif what_i_do == '3':
 
     curs.execute(db_change("update rb set ongoing = '' where block = ?"), [user_data])
 elif what_i_do == '4':
-    print('----')
     host = input('Host : ')
 
     curs.execute(db_change("update other set data = ? where name = 'host'"), [host])
 elif what_i_do == '5':
-    print('----')
     port = int(input('Port : '))
 
     curs.execute(db_change("update other set data = ? where name = 'port'"), [port])
 elif what_i_do == '6':
-    print('----')
     skin = input('Skin name : ')
 
     curs.execute(db_change("update other set data = ? where name = 'skin'"), [skin])
 elif what_i_do == '7':
-    print('----')
     user_name = input('User name : ')
-
-    print('----')
     user_pw = input('User password : ')
-    hashed = pw_encode(user_pw)
 
+    hashed = pw_encode(user_pw)
     curs.execute(db_change("update user_set set data = ? where id = ? and name = 'pw'"), [
         hashed,
         user_name
     ])
 elif what_i_do == '8':
-    print('----')
     new_ver = input('Insert version (0000000) : ')
 
     if new_ver == '':
@@ -166,10 +149,7 @@ elif what_i_do == '9':
     if os.path.exists(os.path.join('data', 'set.json')):
         os.remove(os.path.join('data', 'set.json'))
 elif what_i_do == '10':
-    print('----')
     user_name = input('User name : ')
-
-    print('----')
     new_name = input('New name : ')
 
     curs.execute(
@@ -192,29 +172,24 @@ elif what_i_do == '12':
 elif what_i_do == '14':
     curs.execute(db_change('delete from other where name = "head"'))
 elif what_i_do == '15':
-    print('----')
     user_name = input('User name : ')
 
     curs.execute(db_change("update user_set set data = 'owner' where id = ? and name = 'acl'"), [user_name])
 elif what_i_do == '16':
-    print('----')
     user_name = input('User name : ')
 
     curs.execute(db_change('select data from user_set where name = "2fa" and id = ?'), [user_name])
     if curs.fetchall():
         curs.execute(db_change("update user_set set data = '' where name = '2fa' and id = ?"), [user_name])
 elif what_i_do == '17':
-    print('----')
     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']:
@@ -240,13 +215,11 @@ elif what_i_do == '19':
         else:
             print('Error : update failed')
 elif what_i_do == '20':
-    print('----')
     domain = input('Domain (EX : 2du.pythonanywhere.com) : ')
 
     curs.execute(db_change('delete from other where name = "domain"'))
     curs.execute(db_change('insert into other (name, data, coverage) values ("domain", ?, "")'), [domain])
 elif what_i_do == '21':
-    print('----')
     tls_v = input('TLS (http) [http, https] : ')
     if not tls_v in ['http', 'https']:
         tls_v = 'http'
@@ -288,5 +261,4 @@ if data_db_load == 'Y':
     except:
         pass
 
-print('----')
 print('OK')

+ 2 - 2
lang/en-US.json

@@ -416,7 +416,7 @@
                 "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",
+                "phrase_old_page_warning" : "Warning on previous revision document visit",
             "_comment_" : "Ext_API",
                 "recaptcha" : "reCAPTCHA",
                 "hcaptcha" : "hCAPTCHA",
@@ -613,7 +613,7 @@
             "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.",
             "not_support_skin_warning" : "It does not work on skins that do not support this feature.",
-            "old_page_warring" : "This page is out of date.",
+            "old_page_warning" : "This page is out of date.",
         "_comment_" : "Challenge",
             "challenge_title_register" : "Hello, World!",
             "challenge_info_register" : "Sign up",

+ 2 - 2
lang/ko-KR.json

@@ -411,7 +411,7 @@
     "hcaptcha": "hCAPTCHA",
     "captcha": "CAPTCHA",
     "make_new_topic": "새 토론 생성",
-    "old_page_warring": "이 문서는 오래되었습니다.",
+    "old_page_warning": "이 문서는 오래되었습니다.",
     "challenge_title_register": "Hello, World!",
     "challenge_info_register": "가입을 하세요.",
     "challenge_title_first_contribute": "시작이 반이다.",
@@ -467,7 +467,7 @@
     "document_move_acl": "문서 이동 ACL",
     "document_delete_acl": "문서 삭제 ACL",
     "document_edit_acl": "문서 편집 ACL",
-    "phrase_old_page_warring": "이전 리비전 문서 방문시 경고문",
+    "phrase_old_page_warning": "이전 리비전 문서 방문시 경고문",
     "toc": "목차",
     "topic_view_acl": "토론 보기 ACL",
     "file_delete": "파일 삭제",

+ 1 - 0
route/__init__.py

@@ -55,6 +55,7 @@ from route.list_admin_group import list_admin_group_2
 from route.list_image_file import list_image_file
 from route.list_long_page import list_long_page
 from route.list_old_page import list_old_page
+from route.list_no_link import list_no_link
 from route.list_please import list_please
 from route.list_title_index import list_title_index
 from route.list_user import list_user

+ 1 - 1
route/api_w.py

@@ -80,7 +80,7 @@ def api_w(name = 'Test', tool = '', rev = ''):
         else:
             if tool == '' or tool == 'view':
                 if acl_check(name, 'render') != 1:
-                    if check_int(rev) == '':
+                    if number_check(rev) == '':
                         curs.execute(db_change("select data from data where title = ?"), [name])
                     else:
                         curs.execute(db_change("select data from history where title = ? and id = ?"), [name, rev])

+ 9 - 6
route/edit.py

@@ -49,6 +49,8 @@ def edit_editor(curs, ip, data_main = '', do_type = 'edit', addon = ''):
             
     p_text = html.escape(sql_d[0][0]) if sql_d and sql_d[0][0] != '' else load_lang('default_edit_help')
     
+    monaco_editor_top += '<a href="javascript:do_monaco_to_textarea(); opennamu_do_editor_temp_save();">(' + load_lang('load_temp_save') + ')</a> <a href="javascript:opennamu_do_editor_temp_save_load();">(' + load_lang('load_temp_save_load') + ')</a> '
+    
     monaco_on = get_main_skin_set(curs, flask.session, 'main_css_monaco', ip)
     if monaco_on == 'use':
         editor_display = 'style="display: none;"'
@@ -57,7 +59,7 @@ def edit_editor(curs, ip, data_main = '', do_type = 'edit', addon = ''):
             <script src="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.41.0/min/vs/loader.min.js" integrity="sha512-A+6SvPGkIN9Rf0mUXmW4xh7rDvALXf/f0VtOUiHlDUSPknu2kcfz1KzLpOJyL2pO+nZS13hhIjLqVgiQExLJrw==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
         '''
 
-        monaco_editor_top = '<a href="javascript:opennamu_edit_turn_off_monaco();">(' + load_lang('turn_off_monaco') + ')</a>'
+        monaco_editor_top += '<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'
@@ -76,7 +78,11 @@ def edit_editor(curs, ip, data_main = '', do_type = 'edit', addon = ''):
 
     return add_get_file + '''
         <textarea style="display: none;" id="opennamu_edit_origin" name="doc_data_org">''' + html.escape(data_main) + '''</textarea>
-        <div>''' + monaco_editor_top + ' ' + edit_button('opennamu_edit_textarea', 'opennamu_monaco_editor') + '''</div>
+        <div>
+            ''' + monaco_editor_top + '''
+            <hr class="main_hr">
+            ''' + edit_button() + '''
+        </div>
         
         <div id="opennamu_monaco_editor" class="''' + textarea_size + '''" ''' + monaco_display + '''></div>
         <textarea id="opennamu_edit_textarea" ''' + editor_display + ''' class="''' + textarea_size + '''" name="content" placeholder="''' + p_text + '''">''' + html.escape(data_main) + '''</textarea>
@@ -87,7 +93,7 @@ def edit_editor(curs, ip, data_main = '', do_type = 'edit', addon = ''):
 
         <script>
             do_stop_exit();
-            do_paste_image('opennamu_edit_textarea', 'opennamu_monaco_editor');
+            do_paste_image();
             ''' + add_script + '''
         </script>
                         
@@ -204,9 +210,6 @@ def edit(name = 'Test', section = 0, do_type = ''):
                 leng
             )
             
-            curs.execute(db_change("delete from back where link = ?"), [name])
-            curs.execute(db_change("delete from back where title = ? and type = 'no'"), [name])
-            
             render_set(
                 doc_name = name,
                 doc_data = content,

+ 0 - 3
route/edit_backlink_reset.py

@@ -7,9 +7,6 @@ def edit_backlink_reset(name = 'Test'):
         curs.execute(db_change("select data from data where title = ?"), [name])
         old = curs.fetchall()
         if old:
-            curs.execute(db_change("delete from back where link = ?"), [name])
-            curs.execute(db_change("delete from back where title = ? and type = 'no'"), [name])
-
             render_set(
                 doc_name = name,
                 doc_data = old[0][0],

+ 1 - 0
route/edit_delete.py

@@ -53,6 +53,7 @@ def edit_delete(name):
 
                 curs.execute(db_change("delete from back where link = ?"), [name])
                 curs.execute(db_change("delete from data where title = ?"), [name])
+                
                 conn.commit()
 
             curs.execute(db_change('select data from other where name = "count_all_title"'))

+ 23 - 26
route/edit_revert.py

@@ -37,34 +37,31 @@ def edit_revert(name, num):
             if do_edit_filter(data[0][0]) == 1:
                 return re_error('/error/21')
 
-            curs.execute(db_change("delete from back where link = ?"), [name])
-
-            if data:
-                curs.execute(db_change("select data from data where title = ?"), [name])
-                data_old = curs.fetchall()
-                if data_old:
-                    leng = leng_check(len(data_old[0][0]), len(data[0][0]))
-                    curs.execute(db_change("update data set data = ? where title = ?"), [data[0][0], name])
-                else:
-                    leng = '+' + str(len(data[0][0]))
-                    curs.execute(db_change("insert into data (title, data) values (?, ?)"), [name, data[0][0]])
+            curs.execute(db_change("select data from data where title = ?"), [name])
+            data_old = curs.fetchall()
+            if data_old:
+                leng = leng_check(len(data_old[0][0]), len(data[0][0]))
+                curs.execute(db_change("update data set data = ? where title = ?"), [data[0][0], name])
+            else:
+                leng = '+' + str(len(data[0][0]))
+                curs.execute(db_change("insert into data (title, data) values (?, ?)"), [name, data[0][0]])
 
-                history_plus(
-                    name,
-                    data[0][0],
-                    get_time(),
-                    ip_check(),
-                    flask.request.form.get('send', ''),
-                    leng,
-                    t_check = 'r' + str(num),
-                    mode = 'revert'
-                )
+            history_plus(
+                name,
+                data[0][0],
+                get_time(),
+                ip_check(),
+                flask.request.form.get('send', ''),
+                leng,
+                t_check = 'r' + str(num),
+                mode = 'revert'
+            )
 
-                render_set(
-                    doc_name = name,
-                    doc_data = data[0][0],
-                    data_type = 'backlink'
-                )
+            render_set(
+                doc_name = name,
+                doc_data = data[0][0],
+                data_type = 'backlink'
+            )
 
             conn.commit()
 

+ 13 - 9
route/list_long_page.py

@@ -6,20 +6,24 @@ def list_long_page(tool = 'long_page', arg_num = 1):
 
         sql_num = (arg_num * 50 - 50) if arg_num * 50 > 0 else 0
 
-        curs.execute(db_change('select data from other where name = "count_all_title"'))
-        if int(curs.fetchall()[0][0]) > 30000:
-            return re_error('/error/25')
-
         div = '<ul class="opennamu_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"), [sql_num])
-        db_data = curs.fetchall()
-        for data in db_data:
-            div += '<li>' + str(data[1]) + ' | <a href="/w/' + url_pas(data[0]) + '">' + html.escape(data[0]) + '</a></li>'
+        curs.execute(db_change("select doc_name, set_data from data_set where set_name = 'length' and doc_rev = '' order by set_data + 0 " + select_data + " limit ?, 50"), [sql_num])
+        n_list = curs.fetchall()
+        for data in n_list:
+            div += '<li>'
+            div += data[1] + ' | <a href="/w/' + url_pas(data[0]) + '">' + html.escape(data[0]) + '</a>'
+            
+            curs.execute(db_change("select set_data from data_set where doc_name = ? and set_name = 'doc_type'"), [data[0]])
+            db_data = curs.fetchall()
+            if db_data and db_data[0][0] != '':
+                div += ' | ' + db_data[0][0]
+
+            div += '</li>'
 
-        div += '</ul>' + next_fix('/list/document/' + ('long' if title == 'long_page' else 'short') + '/', arg_num, db_data)
+        div += '</ul>' + next_fix('/list/document/' + ('long' if title == 'long_page' else 'short') + '/', arg_num, n_list)
 
         return easy_minify(flask.render_template(skin_check(),
             imp = [load_lang(title), wiki_set(), wiki_custom(), wiki_css([0, 0])],

+ 30 - 0
route/list_no_link.py

@@ -0,0 +1,30 @@
+from .tool.func import *
+
+def list_no_link(num = 1):
+    with get_db_connect() as conn:
+        curs = conn.cursor()
+        
+        sql_num = (num * 50 - 50) if num * 50 > 0 else 0
+        
+        div = '<ul class="opennamu_ul">'
+        
+        curs.execute(db_change("select doc_name, set_data from data_set where set_name = 'link_count' and doc_rev = '' and set_data = '0' limit ?, 50"), [sql_num])
+        n_list = curs.fetchall()
+        for data in n_list:
+            div += '<li>'
+            div += data[1] + ' | <a href="/w/' + url_pas(data[0]) + '">' + html.escape(data[0]) + '</a>'
+            
+            curs.execute(db_change("select set_data from data_set where doc_name = ? and set_name = 'doc_type'"), [data[0]])
+            db_data = curs.fetchall()
+            if db_data and db_data[0][0] != '':
+                div += ' | ' + db_data[0][0]
+
+            div += '</li>'
+        
+        div += '</ul>' + next_fix('/list/document/no_link/', num, n_list)
+        
+        return easy_minify(flask.render_template(skin_check(),
+            imp = [load_lang('no_link_document_list'), wiki_set(), wiki_custom(), wiki_css([0, 0])],
+            data = div,
+            menu = [['other', load_lang('return')]]
+        ))

+ 9 - 7
route/list_old_page.py

@@ -4,20 +4,22 @@ def list_old_page(num = 1):
     with get_db_connect() as conn:
         curs = conn.cursor()
         
-        # 리다이렉트 구분도 넣을 예정
-        # 그 전에 로직 개편하고
         sql_num = (num * 50 - 50) if num * 50 > 0 else 0
         
-        curs.execute(db_change('select data from other where name = "count_all_title"'))
-        if int(curs.fetchall()[0][0]) > 30000:
-            return re_error('/error/25')
-        
         div = '<ul class="opennamu_ul">'
         
         curs.execute(db_change("select doc_name, set_data from data_set where set_name = 'last_edit' and doc_rev = '' order by set_data asc limit ?, 50"), [sql_num])
         n_list = curs.fetchall()
         for data in n_list:
-            div += '<li>' + data[1] + ' | <a href="/w/' + url_pas(data[0]) + '">' + html.escape(data[0]) + '</a></li>'
+            div += '<li>'
+            div += data[1] + ' | <a href="/w/' + url_pas(data[0]) + '">' + html.escape(data[0]) + '</a>'
+            
+            curs.execute(db_change("select set_data from data_set where doc_name = ? and set_name = 'doc_type'"), [data[0]])
+            db_data = curs.fetchall()
+            if db_data and db_data[0][0] != '':
+                div += ' | ' + db_data[0][0]
+
+            div += '</li>'
         
         div += '</ul>' + next_fix('/list/document/old/', num, n_list)
         

+ 13 - 10
route/main_setting_phrase.py

@@ -28,17 +28,14 @@ def main_setting_phrase():
             'topic_text',
             'phrase_user_page_admin',
             'phrase_user_page_owner',
-            'phrase_old_page_warring',
+            'phrase_old_page_warning',
             'bbs_help',
-            'bbs_comment_help'
+            'bbs_comment_help',
+            'outdated_doc_warning',
+            'outdated_doc_warning_date'
         ]
         if flask.request.method == 'POST':
-            for i in i_list:
-                curs.execute(db_change("update other set data = ? where name = ?"), [
-                    flask.request.form.get(i, ''),
-                    i
-                ])
-
+            curs.executemany(db_change("update other set data = ? where name = ?"), [[flask.request.form.get(for_a, ''), for_a] for for_a in i_list])
             conn.commit()
 
             admin_check(None, 'edit_set (phrase)')
@@ -46,7 +43,6 @@ def main_setting_phrase():
             return redirect('/setting/phrase')
         else:
             d_list = []
-
             for i in i_list:
                 curs.execute(db_change('select data from other where name = ?'), [i])
                 sql_d = curs.fetchall()
@@ -124,7 +120,7 @@ def main_setting_phrase():
                         <h2>''' + load_lang('phrase_user_page_owner') + ''' (HTML)</h2>
                         <textarea class="opennamu_textarea_100" name="''' + i_list[19] + '''">''' + html.escape(d_list[19]) + '''</textarea>
 
-                        <h2>''' + load_lang('phrase_old_page_warring') + ''' (''' + load_lang('beta') + ''') (HTML)</h2>
+                        <h2>''' + load_lang('phrase_old_page_warning') + ''' (''' + load_lang('beta') + ''') (HTML)</h2>
                         <textarea class="opennamu_textarea_100" name="''' + i_list[20] + '''">''' + html.escape(d_list[20]) + '''</textarea>
                         
                         <h2>''' + load_lang('bbs_help') + '''</h2>
@@ -133,6 +129,13 @@ def main_setting_phrase():
                         <h2>''' + load_lang('bbs_comment_help') + '''</h2>
                         <textarea class="opennamu_textarea_100" name="''' + i_list[22] + '''">''' + html.escape(d_list[22]) + '''</textarea>
 
+                        <h2>''' + load_lang('outdated_doc_warning') + '''  (HTML)</h2>
+                        <span>''' + load_lang('period') + '''</span> (''' + load_lang('off') + ''' : ''' + load_lang('empty') + ''')
+                        <hr class="main_hr">
+                        <input name="''' + i_list[24] + '''" value="''' + html.escape(d_list[24]) + '''">
+                        <hr class="main_hr">
+                        <textarea class="opennamu_textarea_100" name="''' + i_list[23] + '''" placeholder="''' + load_lang('old_page_warning') + '''">''' + html.escape(d_list[23]) + '''</textarea>
+
                         <hr class="main_hr">
                         <button id="opennamu_save_button" type="submit">''' + load_lang('save') + '''</button>
                     </form>

+ 0 - 1
route/main_sys_restart.py

@@ -8,7 +8,6 @@ def main_sys_restart():
         if flask.request.method == 'POST':
             admin_check(None, 'restart')
 
-            print('----')
             print('Restart')
 
             python_ver = ''

+ 0 - 1
route/main_sys_shutdown.py

@@ -10,7 +10,6 @@ def main_sys_shutdown():
 
             conn.commit()
 
-            print('----')
             print('Shutdown')
 
             os._exit(0)

+ 1 - 2
route/main_sys_update.py

@@ -17,9 +17,8 @@ def main_sys_update():
             up_data = curs.fetchall()
             up_data = up_data[0][0] if up_data and up_data[0][0] in ['stable', 'beta', 'dev'] else 'stable'
 
-            print('----')
             print('Update')
-            print('----')
+            
             if platform.system() == 'Linux':
                 ok = []
 

+ 1 - 0
route/main_tool_other.py

@@ -29,6 +29,7 @@ def main_tool_other():
                     <li><a href="/list/document/long">''' + load_lang('long_page') + '''</a></li>
                     <li><a href="/list/document/short">''' + load_lang('short_page') + '''</a></li>
                     <li><a href="/list/document/old">''' + load_lang('old_page') + '''</a></li>
+                    <li><a href="/list/document/no_link">''' + load_lang('no_link_document_list') + '''</a></li>
                 </ul>
                 <h3>''' + load_lang('user') + '''</h3>
                 <ul class="opennamu_ul">

+ 8 - 0
route/recent_change.py

@@ -6,11 +6,19 @@ def recent_change_send_render(data):
         data_unescape = html.unescape(match)
 
         return '<a href="/w/' + url_pas(data_unescape) + '">' + match + '</a>'
+    
+    def send_render_link(match):
+        link_main = match[2]
+        link_main = link_main.replace('"', '&quot;')
+
+        return match[1] + '<a href="' + link_main + '">' + link_main + '</a>'
 
     if data == '&lt;br&gt;' or data == '' or re.search(r'^ +$', data):
         data = '<br>'
     else:
         data = data.replace('javascript:', '')
+
+        data = re.sub(r'( |^)(https?:\/\/(?:[^ ]+))', send_render_link, data)
         data = re.sub(r'&lt;a(?:(?:(?!&gt;).)*)&gt;((?:(?!&lt;\/a&gt;).)+)&lt;\/a&gt;', send_render_href_replace, data)
 
     return data

+ 8 - 26
route/tool/func.py

@@ -19,7 +19,6 @@ with open('version.json', encoding = 'utf8') as file_data:
 print('Version : ' + version_list['beta']['r_ver'])
 print('DB set version : ' + version_list['beta']['c_ver'])
 print('Skin set version : ' + version_list['beta']['s_ver'])
-print('----')
 
 # Init-PIP_Install
 data_up_date = 1
@@ -67,8 +66,6 @@ if data_up_date == 1:
         print('Help : try "python3 -m pip install -r requirements.txt"')
 else:
     print('PIP check pass')
-    
-print('----')
 
 # Init-Load
 from .func_tool import *
@@ -352,9 +349,7 @@ def update(ver_num, set_data):
     with get_db_connect() as conn:
         curs = conn.cursor()
 
-        print('----')
         # 업데이트 하위 호환 유지 함수
-
         if ver_num < 3160027:
             print('Add init set')
             set_init()
@@ -749,23 +744,13 @@ def leng_check(A, B):
     # A -> old
     return '0' if A == B else (('-' + str(A - B)) if A > B else ('+' + str(B - A)))
 
-def number_check(data, f=False):
+def number_check(data, f = 0):
     try:
-        if f:
-            float(data)
-        else:
-            int(data)
+        float(data) if f == 1 else int(data)
         return data
     except:
         return '1'
     
-def check_int(data):
-    try:
-        int(data)
-        return data
-    except:
-        return ''
-    
 def redirect(data = '/'):
     return flask.redirect(load_domain('full') + data)
     
@@ -839,7 +824,7 @@ def get_tool_js_safe(data):
 
     return data
 
-def edit_button(ob_name = 'opennamu_edit_textarea', monaco_ob_name = 'opennamu_monaco_editor'):
+def edit_button():
     with get_db_connect() as conn:
         curs = conn.cursor()
 
@@ -852,7 +837,7 @@ def edit_button(ob_name = 'opennamu_edit_textarea', monaco_ob_name = 'opennamu_m
 
         data = ''
         for insert_data in insert_list:
-            data += '<a href="javascript:do_insert_data(\'' + ob_name + '\', \'' + get_tool_js_safe(insert_data[0]) + '\', \'' + monaco_ob_name + '\');">(' + html.escape(insert_data[1]) + ')</a> '
+            data += '<a href="javascript:do_insert_data(\'' + get_tool_js_safe(insert_data[0]) + '\');">(' + html.escape(insert_data[1]) + ')</a> '
 
         data += (' ' if data != '' else '') + '<a href="/filter/edit_top">(' + load_lang('add') + ')</a>'
         data += '<hr class="main_hr">'
@@ -1043,7 +1028,7 @@ def wiki_css(data):
     data_css = ''
     data_css_add = ''
 
-    data_css_ver = '182'
+    data_css_ver = '184'
     data_css_ver = '.cache_v' + data_css_ver
 
     if 'main_css' in global_wiki_set:
@@ -1540,7 +1525,6 @@ def send_email(who, title, data):
 
             return 1
         except Exception as e:
-            print('----')
             print('Error : email send error')
             print(e)
 
@@ -2517,7 +2501,7 @@ def history_plus(title, data, date, ip, send, leng, t_check = '', mode = ''):
             mode = mode if not re.search('^user:', title) else 'user'
 
         send = re.sub(r'\(|\)|<|>', '', send)
-        send = send[:128] if len(send) > 128 else send
+        send = send[:512] if len(send) > 512 else send
         send = send + ' (' + t_check + ')' if t_check != '' else send
 
         if mode != 'add' and mode != 'user':
@@ -2531,15 +2515,13 @@ def history_plus(title, data, date, ip, send, leng, t_check = '', mode = ''):
             data_set_exist = '' if t_check != 'delete' else '1'
 
             curs.execute(db_change("select doc_name from data_set where doc_name = ? and set_name = 'last_edit'"), [title])
-            db_data = curs.fetchall()
-            if db_data:
+            if curs.fetchall():
                 curs.execute(db_change("update data_set set set_data = ?, doc_rev = ? where doc_name = ? and set_name = 'last_edit'"), [date, data_set_exist, title])
             else:
                 curs.execute(db_change("insert into data_set (doc_name, doc_rev, set_name, set_data) values (?, ?, 'last_edit', ?)"), [title, data_set_exist, date])
 
             curs.execute(db_change("select doc_name from data_set where doc_name = ? and set_name = 'length'"), [title])
-            db_data = curs.fetchall()
-            if db_data:
+            if curs.fetchall():
                 curs.execute(db_change("update data_set set set_data = ?, doc_rev = ? where doc_name = ? and set_name = 'length'"), [len(data), data_set_exist, title])
             else:
                 curs.execute(db_change("insert into data_set (doc_name, doc_rev, set_name, set_data) values (?, ?, 'length', ?)"), [title, data_set_exist, len(data)])

+ 23 - 36
route/tool/func_render.py

@@ -40,25 +40,11 @@ class class_do_render:
             rep_data = db_data[0][0] if db_data else 'namumark'
 
         if rep_data == 'namumark' or rep_data == 'namumark_beta':
-            data_end = class_do_render_namumark(
-                curs,
-                doc_name,
-                doc_data,
-                doc_set,
-                self.lang_data
-            )()
+            data_end = class_do_render_namumark(curs, doc_name, doc_data, doc_set, self.lang_data)()
         elif rep_data == 'raw':
-            data_end = [
-                html.escape(doc_data).replace('\n', '<br>'), 
-                '', 
-                {}
-            ]
+            data_end = [html.escape(doc_data).replace('\n', '<br>'), '', {}]
         else:
-            data_end = [
-                doc_data, 
-                '', 
-                {}
-            ]
+            data_end = [doc_data, '', {}]
 
         if data_type == 'thread' or data_type == 'api_thread':
             def do_thread_a_change(match):
@@ -73,31 +59,32 @@ class class_do_render:
                 else:
                     return ''
 
-            data_end[0] = re.sub(
-                r'&lt;(topic_a(?:_post|_thread)?)&gt;((?:(?!&lt;\/topic_a(?:_post|_thread)?&gt;).)+)&lt;\/topic_a(?:_post|_thread)?&gt;',
-                do_thread_a_change,
-                data_end[0]
-            )
-            data_end[0] = re.sub(
-                r'&lt;topic_call&gt;@(?P<in>(?:(?!&lt;\/topic_call&gt;).)+)&lt;\/topic_call&gt;',
-                '<a href="/w/user:\\g<in>">@\\g<in></a>',
-                data_end[0]
-            )
+            data_end[0] = re.sub(r'&lt;(topic_a(?:_post|_thread)?)&gt;((?:(?!&lt;\/topic_a(?:_post|_thread)?&gt;).)+)&lt;\/topic_a(?:_post|_thread)?&gt;', do_thread_a_change, data_end[0])
+            data_end[0] = re.sub(r'&lt;topic_call&gt;@(?P<in>(?:(?!&lt;\/topic_call&gt;).)+)&lt;\/topic_call&gt;', '<a href="/w/user:\\g<in>">@\\g<in></a>', data_end[0])
 
         if data_type == 'backlink':
-            if 'backlink' in data_end[2]:
-                backlink = data_end[2]['backlink']
-            else:
-                backlink = []
+            curs.execute(db_change("delete from back where link = ?"), [doc_name])
+            curs.execute(db_change("delete from back where title = ? and type = 'no'"), [doc_name])
+
+            curs.execute(db_change("delete from data_set where doc_name = ? and set_name = 'link_count'"), [doc_name])
+            curs.execute(db_change("delete from data_set where doc_name = ? and set_name = 'doc_type'"), [doc_name])
 
+            backlink = data_end[2]['backlink'] if 'backlink' in data_end[2] else []
             if backlink != []:
                 curs.executemany(db_change("insert into back (link, title, type, data) values (?, ?, ?, ?)"), data_end[2]['backlink'])
                 curs.execute(db_change("delete from back where title = ? and type = 'no'"), [doc_name])
 
+            link_count = 0
+            if 'link_count' in data_end[2]:
+                link_count = data_end[2]['link_count']
+
+            curs.execute(db_change("insert into data_set (doc_name, doc_rev, set_name, set_data) values (?, '', 'link_count', ?)"), [doc_name, link_count])
+
+            if 'redirect' in data_end[2] and data_end[2]['redirect'] == 1:
+                curs.execute(db_change("insert into data_set (doc_name, doc_rev, set_name, set_data) values (?, '', 'doc_type', 'redirect')"), [doc_name])
+            else:
+                curs.execute(db_change("insert into data_set (doc_name, doc_rev, set_name, set_data) values (?, '', 'doc_type', '')"), [doc_name])
+            
             self.conn.commit()
 
-        return [
-            data_end[0], 
-            data_end[1],
-            data_end[2]
-        ]
+        return [data_end[0], data_end[1], data_end[2]]

+ 87 - 160
route/tool/func_render_namumark.py

@@ -39,6 +39,7 @@ class class_do_render_namumark:
 
         self.data_math_count = 0
         self.data_redirect = 0
+        self.link_count = 0
 
         self.data_toc = ''
         self.data_footnote = {}
@@ -227,14 +228,7 @@ class class_do_render_namumark:
         doc_set = self.doc_set
         doc_set['doc_include'] = doc_include
 
-        data_end = class_do_render_namumark(
-            self.curs,
-            self.doc_name,
-            data,
-            doc_set,
-            self.lang_data,
-            do_type = 'inter'
-        )()
+        data_end = class_do_render_namumark(self.curs, self.doc_name, data, doc_set, self.lang_data, do_type = 'inter')()
 
         self.render_data_js += data_end[1]
         self.data_include += data_end[2]['include']
@@ -242,6 +236,7 @@ class class_do_render_namumark:
         self.data_backlink = dict(self.data_backlink, **data_end[2]['backlink_dict'])
         self.data_temp_storage = dict(self.data_temp_storage, **data_end[2]['temp_storage'][0])
         self.data_temp_storage_count += data_end[2]['temp_storage'][1]
+        self.link_count += data_end[2]['link_count']
 
         return data_end[0]
 
@@ -1197,6 +1192,8 @@ class class_do_render_namumark:
                         link_sub = ''
                         link_sub_storage = link_main_org
 
+                    self.link_count += 1
+
                     data_name = self.get_tool_data_storage('<a class="' + link_exist + ' ' + link_same + '" title="' + link_title + '" href="' + link_main + link_data_sharp + '">' + link_sub_storage, '</a>', link_data_full)
                     self.render_data = re.sub(link_regex, lambda x : ('<' + data_name + '>' + link_sub + '</' + data_name + '>'), self.render_data, 1)
 
@@ -2054,44 +2051,7 @@ class class_do_render_namumark:
             quote_count_max -= 1
             quote_count += 1
 
-        # 일반 리스트
-        list_style = {
-            1 : 'opennamu_list_1',
-            2 : 'opennamu_list_2',
-            3 : 'opennamu_list_3',
-            4 : 'opennamu_list_4'
-        }
-        def do_render_list_sub(match):
-            list_data = match.group(2)
-            list_len = len(match.group(1))
-            if list_len == 0:
-                list_len = 1
-
-            list_style_data = 'opennamu_list_5'
-            if list_len in list_style:
-                list_style_data = list_style[list_len]
-
-            return '<li style="margin-left: ' + str(list_len * 20) + 'px;" class="' + list_style_data + '">' + list_data + '</li>'
-
-        list_regex = r'((?:\n *\* ?[^\n]*)+)\n'
-        list_count_max = len(re.findall(list_regex, self.render_data)) * 3
-        while 1:
-            list_data = re.search(list_regex, self.render_data)
-            if list_count_max < 0:
-                break
-            elif not list_data:
-                break
-            else:
-                list_data = list_data.group(1)
-                list_sub_regex = r'\n( *)\* ?([^\n]*)'
-
-                list_data = re.sub(list_sub_regex, do_render_list_sub, list_data)
-
-                self.render_data = re.sub(list_regex, lambda x : ('\n<front_br><ul class="opennamu_ul">' + list_data + '</ul><back_br>\n'), self.render_data, 1)
-
-            list_count_max -= 1
-
-        # 기타 리스트 공통 파트
+        # 리스트 공통 파트
         def int_to_alpha(num):
             alpha_list = string.ascii_lowercase
             alpha_len = len(alpha_list)
@@ -2124,128 +2084,84 @@ class class_do_render_namumark:
             
         list_view_set = get_main_skin_set(self.curs, self.flask_session, 'main_css_list_view_change', self.ip)
         
+        list_style = {
+            1 : 'opennamu_list_1',
+            2 : 'opennamu_list_2',
+            3 : 'opennamu_list_3',
+            4 : 'opennamu_list_4'
+        }
         class do_render_list_int_to:
-            def __init__(self, do_type, list_view_set = ''):
-                self.list_num = []
-                self.do_type = do_type
+            def __init__(self, list_view_set = ''):
+                self.list_num = {}
                 self.list_view_set = list_view_set
 
             def __call__(self, match):
-                list_data = match.group(3)
-                list_start = match.group(2)
-                list_len = len(match.group(1))
-                if list_len == 0:
-                    list_len = 1
+                if match.group(4):
+                    list_data = match.group(5)
+                    list_len = len(match.group(1))
+                    if list_len == 0:
+                        list_len = 1
 
-                if len(self.list_num) >= list_len:
-                    self.list_num[list_len - 1] += 1
+                    list_style_data = 'opennamu_list_5'
+                    if list_len in list_style:
+                        list_style_data = list_style[list_len]
 
-                    for for_a in range(list_len, len(self.list_num)):
-                        self.list_num[for_a] = 0
+                    return '<li style="margin-left: ' + str(list_len * 20) + 'px;" class="' + list_style_data + '">' + list_data + '</li>'
                 else:
-                    self.list_num += [1] * (list_len - len(self.list_num))
-
-                if list_start:
-                    self.list_num[list_len - 1] = int(list_start)
-
-                if self.do_type == 'int':
-                    if self.list_view_set == 'on':
-                        change_text = str('-'.join([str(for_a) for for_a in self.list_num if for_a != 0]))
-                    else:
-                        change_text = str(self.list_num[list_len - 1])
-                elif self.do_type == 'roman_big':
-                    change_text = int_to_roman(self.list_num[list_len - 1]).upper()
-                elif self.do_type == 'roman_small':
-                    change_text = int_to_roman(self.list_num[list_len - 1]).lower()
-                elif self.do_type == 'alpha_big':
-                    change_text = int_to_alpha(self.list_num[list_len - 1]).upper()
-                else:
-                    change_text = int_to_alpha(self.list_num[list_len - 1]).lower()
-
-                return '<li style="margin-left: ' + str((list_len - 1) * 20) + 'px;" class="opennamu_list_none">' + change_text + '. ' + list_data + '</li>'
-
-        # 숫자 리스트
-        list_regex = r'((?:\n *1\. ?[^\n]*){2,})\n'
-        list_count_max = len(re.findall(list_regex, self.render_data)) * 3
-        while 1:
-            list_data = re.search(list_regex, self.render_data)
-            if list_count_max < 0:
-                break
-            elif not list_data:
-                break
-            else:
-                list_data = list_data.group(1)
-                list_sub_regex = r'\n( *)1\.(?:#([0-9]*))? ?([^\n]*)'
-
-                list_class = do_render_list_int_to('int', list_view_set)
-                list_data = re.sub(list_sub_regex, list_class, list_data)
-
-                self.render_data = re.sub(list_regex, lambda x : ('\n<front_br><ul class="opennamu_ul">' + list_data + '</ul><back_br>\n'), self.render_data, 1)
-
-            list_count_max -= 1
-
-        # 소문자 리스트
-        list_regex = r'((?:\n *a\. ?[^\n]*){2,})\n'
-        list_count_max = len(re.findall(list_regex, self.render_data)) * 3
-        while 1:
-            list_data = re.search(list_regex, self.render_data)
-            if list_count_max < 0:
-                break
-            elif not list_data:
-                break
-            else:
-                list_data = list_data.group(1)
-                list_sub_regex = r'\n( *)a.(?:#([0-9]*))? ?([^\n]*)'
-
-                list_class = do_render_list_int_to('alpha_small')
-                list_data = re.sub(list_sub_regex, list_class, list_data)
-
-                self.render_data = re.sub(list_regex, lambda x : ('\n<front_br><ul class="opennamu_ul">' + list_data + '</ul><back_br>\n'), self.render_data, 1)
-
-            list_count_max -= 1
-
-        # 대문자 리스트
-        list_regex = r'((?:\n *A\. ?[^\n]*){2,})\n'
-        list_count_max = len(re.findall(list_regex, self.render_data)) * 3
-        while 1:
-            list_data = re.search(list_regex, self.render_data)
-            if list_count_max < 0:
-                break
-            elif not list_data:
-                break
-            else:
-                list_data = list_data.group(1)
-                list_sub_regex = r'\n( *)A.(?:#([0-9]*))? ?([^\n]*)'
+                    list_type = match.group(2)
+
+                    do_type = 'int'
+                    if list_type == 'a':
+                        do_type = 'alpha_small'
+                    elif list_type == 'A':
+                        do_type = 'alpha_big'
+                    elif list_type == 'i':
+                        do_type = 'roman_small'
+                    elif list_type == 'I':
+                        do_type = 'roman_big'
+
+                    if not do_type in self.list_num:
+                        self.list_num[do_type] = []
+                    
+                    for for_a in self.list_num:
+                        if for_a != do_type:
+                            self.list_num[for_a] = []
 
-                list_class = do_render_list_int_to('alpha_big')
-                list_data = re.sub(list_sub_regex, list_class, list_data)
+                    list_data = match.group(5)
+                    list_start = match.group(3)
+                    list_len = len(match.group(1))
+                    if list_len == 0:
+                        list_len = 1
 
-                self.render_data = re.sub(list_regex, lambda x : ('\n<front_br><ul class="opennamu_ul">' + list_data + '</ul><back_br>\n'), self.render_data, 1)
+                    if len(self.list_num[do_type]) >= list_len:
+                        self.list_num[do_type][list_len - 1] += 1
 
-            list_count_max -= 1
-
-        # 로마자 대문자 리스트
-        list_regex = r'((?:\n *I\. ?[^\n]*){2,})\n'
-        list_count_max = len(re.findall(list_regex, self.render_data)) * 3
-        while 1:
-            list_data = re.search(list_regex, self.render_data)
-            if list_count_max < 0:
-                break
-            elif not list_data:
-                break
-            else:
-                list_data = list_data.group(1)
-                list_sub_regex = r'\n( *)I.(?:#([0-9]*))? ?([^\n]*)'
+                        for for_a in range(list_len, len(self.list_num[do_type])):
+                            self.list_num[do_type][for_a] = 0
+                    else:
+                        self.list_num[do_type] += [1] * (list_len - len(self.list_num[do_type]))
 
-                list_class = do_render_list_int_to('roman_big')
-                list_data = re.sub(list_sub_regex, list_class, list_data)
+                    if list_start:
+                        self.list_num[do_type][list_len - 1] = int(list_start)
 
-                self.render_data = re.sub(list_regex, lambda x : ('\n<front_br><ul class="opennamu_ul">' + list_data + '</ul><back_br>\n'), self.render_data, 1)
+                    if do_type == 'int':
+                        if self.list_view_set == 'on':
+                            change_text = str('-'.join([str(for_a) for for_a in self.list_num[do_type] if for_a != 0]))
+                        else:
+                            change_text = str(self.list_num[do_type][list_len - 1])
+                    elif do_type == 'roman_big':
+                        change_text = int_to_roman(self.list_num[do_type][list_len - 1]).upper()
+                    elif do_type == 'roman_small':
+                        change_text = int_to_roman(self.list_num[do_type][list_len - 1]).lower()
+                    elif do_type == 'alpha_big':
+                        change_text = int_to_alpha(self.list_num[do_type][list_len - 1]).upper()
+                    else:
+                        change_text = int_to_alpha(self.list_num[do_type][list_len - 1]).lower()
 
-            list_count_max -= 1
+                    return '<li style="margin-left: ' + str((list_len - 1) * 20) + 'px;" class="opennamu_list_none">' + change_text + '. ' + list_data + '</li>'
 
-        # 로마자 소문자 리스트
-        list_regex = r'((?:\n *i\. ?[^\n]*){2,})\n'
+        # 숫자 리스트
+        list_regex = r'((?:\n( *)(?:(1|a|A|I|i)\.(?:#([0-9]*))?|(\*)) ?([^\n]*))+)\n'
         list_count_max = len(re.findall(list_regex, self.render_data)) * 3
         while 1:
             list_data = re.search(list_regex, self.render_data)
@@ -2255,9 +2171,9 @@ class class_do_render_namumark:
                 break
             else:
                 list_data = list_data.group(1)
-                list_sub_regex = r'\n( *)i.(?:#([0-9]*))? ?([^\n]*)'
+                list_sub_regex = r'\n( *)(?:(1|a|A|I|i)\.(?:#([0-9]*))?|(\*)) ?([^\n]*)'
 
-                list_class = do_render_list_int_to('roman_small')
+                list_class = do_render_list_int_to(list_view_set)
                 list_data = re.sub(list_sub_regex, list_class, list_data)
 
                 self.render_data = re.sub(list_regex, lambda x : ('\n<front_br><ul class="opennamu_ul">' + list_data + '</ul><back_br>\n'), self.render_data, 1)
@@ -2327,17 +2243,25 @@ class class_do_render_namumark:
             
         self.render_data = re.sub(r'(<a(?: [^<>]*)?>|<\/a>)', do_render_last_a_link, self.render_data)
         
+        def do_render_last_toc_filter(match):
+            data = match.group(1).split(' ')
+            if data[0] == 'a' or data[0] == '/a':
+                return '<' + match[1] + '>'
+            else:
+                return ''
+
         # add toc
         def do_render_last_toc(match):
             data = match.group(1)
-
-            data = re.sub(r'<[^<>]*>', '', data)
+            
+            data_sub = re.sub(r'<([^<>]*)>', '', data)
+            data = re.sub(r'<([^<>]*)>', do_render_last_toc_filter, data)
 
             heading_regex = r'<h([1-6])>'
             heading_data = re.search(heading_regex, self.render_data)
             if heading_data:
                 heading_data = heading_data.group(1)
-                self.render_data = re.sub(heading_regex, lambda x : ('<h' + heading_data + ' id="' + data + '">'), self.render_data, 1)
+                self.render_data = re.sub(heading_regex, lambda x : ('<h' + heading_data + ' id="' + data_sub + '">'), self.render_data, 1)
             
             return data
 
@@ -2421,6 +2345,7 @@ class class_do_render_namumark:
         data_backlink_dict = self.data_backlink
         self.data_backlink = [[self.doc_name, for_a, for_b, self.data_backlink[for_a][for_b]] for for_a in self.data_backlink for for_b in self.data_backlink[for_a]]
 
+        # 여기 수정시 do_inter_render도 수정 필요
         return [
             self.render_data, # html
             self.render_data_js, # js
@@ -2430,6 +2355,8 @@ class class_do_render_namumark:
                 'include' : self.data_include, # include data
                 'footnote' : self.data_footnote_all, # footnote
                 'category' : self.data_category_list,
-                'temp_storage' : [self.data_temp_storage, self.data_temp_storage_count]
+                'temp_storage' : [self.data_temp_storage, self.data_temp_storage_count],
+                'link_count' : self.link_count,
+                'redirect' : self.data_redirect
             } # other
         ]

+ 21 - 2
route/view_read.py

@@ -11,6 +11,9 @@ def view_read(name = 'Test', doc_rev = '', doc_from = '', do_type = ''):
         category_total = ''
         file_data = ''
 
+        doc_type = ''
+        now_time = get_time()
+
         ip = ip_check()
             
         uppage = re.sub(r"/([^/]+)$", '', name)
@@ -25,6 +28,7 @@ def view_read(name = 'Test', doc_rev = '', doc_from = '', do_type = ''):
 
         if re.search(r'^category:', name):
             name_view = name
+            doc_type = 'category'
 
             category_doc = ''
             category_sub = ''
@@ -79,6 +83,7 @@ def view_read(name = 'Test', doc_rev = '', doc_from = '', do_type = ''):
                 ''
         elif re.search(r"^user:([^/]*)", name):
             name_view = name
+            doc_type = 'user'
 
             match = re.search(r"^user:([^/]*)", name)
             
@@ -109,9 +114,10 @@ def view_read(name = 'Test', doc_rev = '', doc_from = '', do_type = ''):
                 <hr class="main_hr">
             '''
             if name == 'user:' + user_name:
-                menu += [['w/' + url_pas(name) + '/' + url_pas(get_time().split()[0]), load_lang('today_doc')]]
+                menu += [['w/' + url_pas(name) + '/' + url_pas(now_time.split()[0]), load_lang('today_doc')]]
         elif re.search(r"^file:", name):
             name_view = name
+            doc_type = 'file'
 
             mime_type = re.search(r'([^.]+)$', name)
             if mime_type:
@@ -278,11 +284,24 @@ def view_read(name = 'Test', doc_rev = '', doc_from = '', do_type = ''):
         div = file_data + user_doc + end_data + category_total
 
         if num != '':
-            curs.execute(db_change('select data from other where name = "phrase_old_page_warring"'))
+            curs.execute(db_change('select data from other where name = "phrase_old_page_warning"'))
             db_data = curs.fetchall()
             if db_data and db_data[0][0] != '':
                 div = db_data[0][0] + '<hr class="main_hr">' + div
 
+            doc_type = 'rev'
+        
+        if doc_type == '':
+            curs.execute(db_change('select data from other where name = "outdated_doc_warning_date"'))
+            db_data = curs.fetchall()
+            if db_data and db_data[0][0] != '' and r_date != 0:
+                time_1 = datetime.datetime.strptime(r_date, '%Y-%m-%d %H:%M:%S') + datetime.timedelta(days = int(number_check(db_data[0][0])))
+                time_2 = datetime.datetime.strptime(now_time, '%Y-%m-%d %H:%M:%S')
+                if time_2 > time_1:
+                    curs.execute(db_change('select data from other where name = "outdated_doc_warning"'))
+                    db_data = curs.fetchall()
+                    div = (db_data[0][0] if db_data and db_data[0][0] != '' else load_lang('old_page_warning')) + '<hr class="main_hr">' + div
+
         curs.execute(db_change("select data from other where name = 'body'"))
         body = curs.fetchall()
         div = (body[0][0] + div) if body else div

+ 12 - 5
route/view_xref.py

@@ -1,22 +1,19 @@
 from .tool.func import *
 
-def view_xref(name = 'Test', xref_type = 1):
+def view_xref(name = 'Test', xref_type = 1, num = 1):
     with get_db_connect() as conn:
         curs = conn.cursor()
 
         if acl_check(name, 'render') == 1:
             return re_error('/ban')
 
-        num = int(number_check(flask.request.args.get('num', '1')))
         sql_num = (num * 50 - 50) if num * 50 > 0 else 0
 
         if xref_type == 1:
             div = '<a href="/xref_this/' + url_pas(name) + '">(' + load_lang('link_in_this') + ')</a><hr class="main_hr">'
-
             data_sub = '(' + load_lang('backlink') + ')'
         else:
             div = '<a href="/xref/' + url_pas(name) + '">(' + load_lang('normal') + ')</a><hr class="main_hr">'
-
             data_sub = '(' + load_lang('link_in_this') + ')'
 
         div += '<ul class="opennamu_ul">'
@@ -25,6 +22,11 @@ def view_xref(name = 'Test', xref_type = 1):
         db_data = curs.fetchall()
         link_case_insensitive = ' collate nocase' if db_data and db_data[0][0] != '' else ''
 
+        if xref_type == 2:
+            curs.execute(db_change("select set_data from data_set where doc_name = ? and set_name = 'link_count'"), [name])
+            db_data = curs.fetchall()
+            div += '<li>' + load_lang('link_count') + ' : ' +  (db_data[0][0] if db_data else load_lang('data_missing')) + '</li>'
+
         sql_insert = ['link', 'title'] if xref_type == 1 else ['title', 'link']
         curs.execute(db_change("select distinct " + sql_insert[0] + ", type from back where " + sql_insert[1] + " = ?" + link_case_insensitive + " and not type = 'no' and not type = 'nothing' order by type asc, " + sql_insert[0] + " asc limit ?, 50"), [name, sql_num])
         data_list = curs.fetchall()
@@ -41,7 +43,12 @@ def view_xref(name = 'Test', xref_type = 1):
 
             div += '</li>'
 
-        div += '</ul>' + next_fix('/xref/' + url_pas(name) + '?change=' + str(xref_type) + '&num=', num, data_list)
+        div += '</ul>'
+        
+        if xref_type == 2:
+            div += get_next_page_bottom('/xref_this_page/{}/' + url_pas(name), num, data_list)
+        else:
+            div += get_next_page_bottom('/xref_page/{}/' + url_pas(name), num, data_list)
 
         return easy_minify(flask.render_template(skin_check(),
             imp = [name, wiki_set(), wiki_custom(), wiki_css([data_sub, 0])],

+ 0 - 4
test_tool.py

@@ -17,14 +17,10 @@ load_db = get_db_connect()
 conn = load_db.__enter__()
 curs = conn.cursor()
 
-print('----')
 print('1. Add virtual doc')
 
-print('----')
 what_i_do = input('Select : ')
-
 if what_i_do == '1':
-    print('----')
     doc_count = int(input('Count : '))
     
     for for_a in range(doc_count):

+ 1 - 1
version.json

@@ -1,6 +1,6 @@
 {
     "beta" : {
-        "r_ver" : "v3.4.6-RC5-dev32",
+        "r_ver" : "v3.4.6-RC5-dev38",
         "c_ver" : "3500373",
         "s_ver" : "3500112"
     }

+ 8 - 2
views/main_css/js/route/editor.js

@@ -1,6 +1,9 @@
 "use strict";
 
-function do_insert_data(name, data, monaco_name) {
+function do_insert_data(data) {
+    const name = 'opennamu_edit_textarea';
+    const monaco_name = 'opennamu_monaco_editor';
+
     if(!document.getElementById(monaco_name)) {
         // https://stackoverflow.com/questions/11076975/insert-text-into-textarea-at-cursor-position-javascript
         if(document.selection) {
@@ -36,7 +39,10 @@ function do_insert_data(name, data, monaco_name) {
 }
 
 // 아직 개편이 더 필요함
-function do_paste_image(name, monaco_name) {
+function do_paste_image() {
+    const name = 'opennamu_edit_textarea';
+    const monaco_name = 'opennamu_monaco_editor';
+
     window.addEventListener('DOMContentLoaded', async function() {
         let set = await opennamu_get_main_skin_set("main_css_image_paste");
         if(set === 'use') {

+ 21 - 1
views/main_css/js/route/editor_sub.js

@@ -6,7 +6,7 @@ function opennamu_do_editor_preview() {
         if (doc_name_input !== null) {
             doc_name = doc_name_input.value;
         }
-        fetch("/api/w_tool/preview/" + opennamu_do_url_encode(doc_name), {
+        fetch("/api/w_tool/preview/" + (opennamu_do_url_encode(doc_name)), {
             method: 'POST',
             headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
             body: new URLSearchParams({
@@ -23,3 +23,23 @@ function opennamu_do_editor_preview() {
         });
     }
 }
+function opennamu_do_editor_temp_save() {
+    var input = document.querySelector('#opennamu_edit_textarea');
+    if (input !== null) {
+        localStorage.setItem("key", input.value);
+    }
+}
+function opennamu_do_editor_temp_save_load() {
+    var data = localStorage.getItem("key");
+    console.log(data);
+    if (data !== null) {
+        var input = document.querySelector('#opennamu_edit_textarea');
+        if (input !== null) {
+            input.value = data;
+        }
+        var input_2 = document.querySelector('#opennamu_monaco_editor');
+        if (input_2 !== null) {
+            window.editor.setValue(data);
+        }
+    }
+}

+ 29 - 1
views/main_css/js/route/editor_sub.ts

@@ -1,3 +1,8 @@
+declare function opennamu_do_url_encode(data : any) : string;
+interface Window {
+    editor? : any;
+}
+
 function opennamu_do_editor_preview() {
     const input = document.querySelector('#opennamu_edit_textarea') as HTMLInputElement | null;
     if(input !== null) {
@@ -8,7 +13,7 @@ function opennamu_do_editor_preview() {
             doc_name = doc_name_input.value;
         }
 
-        fetch("/api/w_tool/preview/" + (opennamu_do_url_encode(doc_name) as (arg1 : string) => string), {
+        fetch("/api/w_tool/preview/" + (opennamu_do_url_encode(doc_name)), {
             method : 'POST',
             headers : { 'Content-Type': 'application/x-www-form-urlencoded' },
             body : new URLSearchParams({
@@ -24,4 +29,27 @@ function opennamu_do_editor_preview() {
             }
         });
     }
+}
+
+function opennamu_do_editor_temp_save() {
+    const input = document.querySelector('#opennamu_edit_textarea') as HTMLInputElement | null;
+    if(input !== null) {
+        localStorage.setItem("key", input.value);
+    }
+}
+
+function opennamu_do_editor_temp_save_load() {
+    const data = localStorage.getItem("key");
+    console.log(data);
+    if(data !== null) {
+        const input = document.querySelector('#opennamu_edit_textarea') as HTMLInputElement | null;
+        if(input !== null) {
+            input.value = data;
+        }
+
+        const input_2 = document.querySelector('#opennamu_monaco_editor') as any;
+        if(input_2 !== null) {
+            window.editor.setValue(data);
+        }
+    }
 }

+ 1 - 1
views/ringo/info.json

@@ -1,5 +1,5 @@
 {
     "name" : "Ringo",
-    "skin_ver" : "v1.0.4",
+    "skin_ver" : "v1.0.5",
     "require_ver" : "3500112"
 }

+ 32 - 8
views/ringo/js/skin_set.js

@@ -3,27 +3,47 @@ function ringo_do_regex_data(data) {
 }
 
 function ringo_get_post() {
-    check = document.getElementById('invert');
+    const check = document.getElementById('invert');
     if(check.checked === true) {
         document.cookie = 'main_css_darkmode=1; path=/';
     } else {
         document.cookie = 'main_css_darkmode=0; path=/';
     }
 
+    const check_2 = document.getElementById('use_sys_darkmode');
+    if(check_2.checked === true) {
+        document.cookie = 'main_css_use_sys_darkmode=1; path=/';
+    } else {
+        document.cookie = 'main_css_use_sys_darkmode=0; path=/';
+    }
+
     history.go(0);
 }
 
 function ringo_do_skin_set() {
     let cookies = document.cookie;
+    if(!cookies.match(ringo_do_regex_data('main_css_use_sys_darkmode')) || (cookies.match(ringo_do_regex_data('main_css_use_sys_darkmode')) && cookies.match(ringo_do_regex_data('main_css_use_sys_darkmode'))[1] === '1')) {
+        if(window.matchMedia('(prefers-color-scheme: dark)').matches) {
+            document.cookie = 'main_css_darkmode=1; path=/';
+        } else {
+            document.cookie = 'main_css_darkmode=0; path=/';
+        }
+    }
+}
+
+function ringo_load_skin_set() {
+    let cookies = document.cookie;
     
     if(window.location.pathname === '/change/skin_set') {
         let set_language = {
             "en-US" : {
                 "save" : "Save",
-                "darkmode" : "Darkmode"
+                "darkmode" : "Darkmode",
+                "use_sys_darkmode" : "Use system darkmode set",
             }, "ko-KR" : {
                 "save" : "저장",
-                "darkmode" : "다크모드"
+                "darkmode" : "다크모드",
+                "use_sys_darkmode" : "시스템 다크모드 설정 사용",
             }
         }
 
@@ -39,14 +59,17 @@ function ringo_do_skin_set() {
 
         let set_data = {};
 
-        if(
-            cookies.match(ringo_do_regex_data('main_css_darkmode')) &&
-            cookies.match(ringo_do_regex_data('main_css_darkmode'))[1] === '1'
-        ) {
+        if(cookies.match(ringo_do_regex_data('main_css_darkmode')) && cookies.match(ringo_do_regex_data('main_css_darkmode'))[1] === '1') {
             set_data["invert"] = "checked";
         }
 
+        if(!cookies.match(ringo_do_regex_data('main_css_use_sys_darkmode')) || (cookies.match(ringo_do_regex_data('main_css_use_sys_darkmode')) && cookies.match(ringo_do_regex_data('main_css_use_sys_darkmode'))[1] === '1')) {
+            set_data["use_sys_darkmode"] = "checked";
+        }
+
         document.getElementById("main_skin_set").innerHTML = ' \
+            <input ' + set_data["use_sys_darkmode"] + ' type="checkbox" id="use_sys_darkmode" name="use_sys_darkmode" value="use_sys_darkmode"> ' + set_language[language]['use_sys_darkmode'] + ' \
+            <hr class="main_hr"> \
             <input ' + set_data["invert"] + ' type="checkbox" id="invert" name="invert" value="invert"> ' + set_language[language]['darkmode'] + ' \
             <hr class="main_hr"> \
             <button onclick="ringo_get_post();">' + set_language[language]['save'] + '</button> \
@@ -54,4 +77,5 @@ function ringo_do_skin_set() {
     }
 }
 
-window.addEventListener('DOMContentLoaded', ringo_do_skin_set);
+window.addEventListener('DOMContentLoaded', ringo_do_skin_set);
+window.addEventListener('DOMContentLoaded', ringo_load_skin_set);

+ 1 - 1
views/tenshi/info.json

@@ -1,5 +1,5 @@
 {
     "name" : "Tenshi",
-    "skin_ver" : "v2.0.6",
+    "skin_ver" : "v2.0.7",
     "require_ver" : "3500110"
 }

+ 32 - 8
views/tenshi/js/skin_set.js

@@ -3,27 +3,47 @@ function ringo_do_regex_data(data) {
 }
 
 function ringo_get_post() {
-    check = document.getElementById('invert');
+    const check = document.getElementById('invert');
     if(check.checked === true) {
         document.cookie = 'main_css_darkmode=1; path=/';
     } else {
         document.cookie = 'main_css_darkmode=0; path=/';
     }
 
+    const check_2 = document.getElementById('use_sys_darkmode');
+    if(check_2.checked === true) {
+        document.cookie = 'main_css_use_sys_darkmode=1; path=/';
+    } else {
+        document.cookie = 'main_css_use_sys_darkmode=0; path=/';
+    }
+
     history.go(0);
 }
 
 function ringo_do_skin_set() {
     let cookies = document.cookie;
+    if(!cookies.match(ringo_do_regex_data('main_css_use_sys_darkmode')) || (cookies.match(ringo_do_regex_data('main_css_use_sys_darkmode')) && cookies.match(ringo_do_regex_data('main_css_use_sys_darkmode'))[1] === '1')) {
+        if(window.matchMedia('(prefers-color-scheme: dark)').matches) {
+            document.cookie = 'main_css_darkmode=1; path=/';
+        } else {
+            document.cookie = 'main_css_darkmode=0; path=/';
+        }
+    }
+}
+
+function ringo_load_skin_set() {
+    let cookies = document.cookie;
     
     if(window.location.pathname === '/change/skin_set') {
         let set_language = {
             "en-US" : {
                 "save" : "Save",
-                "darkmode" : "Darkmode"
+                "darkmode" : "Darkmode",
+                "use_sys_darkmode" : "Use system darkmode set",
             }, "ko-KR" : {
                 "save" : "저장",
-                "darkmode" : "다크모드"
+                "darkmode" : "다크모드",
+                "use_sys_darkmode" : "시스템 다크모드 설정 사용",
             }
         }
 
@@ -39,14 +59,17 @@ function ringo_do_skin_set() {
 
         let set_data = {};
 
-        if(
-            cookies.match(ringo_do_regex_data('main_css_darkmode')) &&
-            cookies.match(ringo_do_regex_data('main_css_darkmode'))[1] === '1'
-        ) {
+        if(cookies.match(ringo_do_regex_data('main_css_darkmode')) && cookies.match(ringo_do_regex_data('main_css_darkmode'))[1] === '1') {
             set_data["invert"] = "checked";
         }
 
+        if(!cookies.match(ringo_do_regex_data('main_css_use_sys_darkmode')) || (cookies.match(ringo_do_regex_data('main_css_use_sys_darkmode')) && cookies.match(ringo_do_regex_data('main_css_use_sys_darkmode'))[1] === '1')) {
+            set_data["use_sys_darkmode"] = "checked";
+        }
+
         document.getElementById("main_skin_set").innerHTML = ' \
+            <input ' + set_data["use_sys_darkmode"] + ' type="checkbox" id="use_sys_darkmode" name="use_sys_darkmode" value="use_sys_darkmode"> ' + set_language[language]['use_sys_darkmode'] + ' \
+            <hr class="main_hr"> \
             <input ' + set_data["invert"] + ' type="checkbox" id="invert" name="invert" value="invert"> ' + set_language[language]['darkmode'] + ' \
             <hr class="main_hr"> \
             <button onclick="ringo_get_post();">' + set_language[language]['save'] + '</button> \
@@ -54,4 +77,5 @@ function ringo_do_skin_set() {
     }
 }
 
-window.addEventListener('DOMContentLoaded', ringo_do_skin_set);
+window.addEventListener('DOMContentLoaded', ringo_do_skin_set);
+window.addEventListener('DOMContentLoaded', ringo_load_skin_set);