Jelajahi Sumber

Implement regisration approval system

LiteHell 6 tahun lalu
induk
melakukan
69701198fc

+ 9 - 0
app.py

@@ -146,6 +146,7 @@ create_data['all_data'] = [
     'inter',
     'html_filter',
     'oauth_conn',
+    'user_application'
 ]
 for i in create_data['all_data']:
     try:
@@ -175,6 +176,7 @@ if setup_tool != 0:
     create_data['rd'] = ['title', 'sub', 'date', 'band', 'stop', 'agree']
     create_data['user'] = ['id', 'pw', 'acl', 'date', 'encode']
     create_data['user_set'] = ['name', 'id', 'data']
+    create_data['user_application'] = ['id', 'pw', 'date', 'encode', 'question', 'answer', 'ip', 'ua', 'token']
     create_data['ban'] = ['block', 'end', 'why', 'band', 'login']
     create_data['topic'] = ['id', 'title', 'sub', 'data', 'date', 'ip', 'block', 'top', 'code']
     create_data['rb'] = ['block', 'end', 'today', 'blocker', 'why', 'band']
@@ -684,6 +686,13 @@ def main_views(name = None):
 def main_file(data = None):
     return main_file_2(conn, data)
 
+@app.route('/application_submitted')
+def application_submitted():
+    return application_submitted_2(conn)
+
+@app.route('/applications', methods = ['POST', 'GET'])
+def applications():
+    return applications_2(conn)
 # End
 @app.errorhandler(404)
 def main_error_404(e):

+ 16 - 1
language/en-US.json

@@ -233,6 +233,8 @@
                 "google_imap_required" : "Google IMAP setting required",
                 "update_branch" : "Branch to import updates",
                 "slow_edit" : "Continuous edit limit",
+                "requires_approval" : "Requires approval for register",
+                "approval_question": "Registeration questions",
             "_comment_2.2.3_" : "Text",
                 "register_text" : "Terms of sign-up",
                 "non_login_alert" : "Non-login alert",
@@ -298,7 +300,18 @@
                 "user_document_acl" : "User document ACL",
                 "upload_acl" : "Upload ACL",
                 "edit_req_acl" : "Edit request ACL",
+        "_comment_2.7_" : "Application list",
+            "application_list": "Application list",
+            "application_time": "Application time",
+            "answer": "Answer",
+            "approve": "Approve",
+            "decline": "Decline",
+            "approve_or_decline": "Approve or reject",
+            "no_applications_now" : "There is no applications.",
+            "approval_requirement_disabled": "Approval requirement is disabled now. You can enabled this on settings",
     "_comment_3_" : "Long",
+        "application_submitted": "Applicatied successfully for registration",
+        "waiting_for_approval": "Application for registration has been made successfully. Please wait for approval by administrators.",
         "ie_no_data_required" : "Operation cannot continue because all required data has not been collected.",
         "oauth_settings_not_found" : "The administrator has not provided any data about using this feature.",
         "oauth_disabled" : "The administrator has disabled this feature.",
@@ -311,6 +324,7 @@
         "markup_enabled" : "Markup enabled",
         "many_delete_help" : "Please write down the document[s] name one by one on the line.",
         "sqlite_only" : "SQLite only",
+        "approval_question_visible_only_when_approval_on" : "Approval questions are visible only when approval requirement is on",
         "_comment_3.1_" : "Error",
             "update_error" : "Auto update is not supported.",
             "inter_error" : "Internal error.",
@@ -338,5 +352,6 @@
             "regex_error" : "There is an error in the regular expression.",
             "decument_404_error" : "This document does not exist.",
             "fast_edit_error" : "You can edit another document after this period (Second(s)) : ",
-            "too_many_dec_error" : "This feature is not supported because there are too many documents."
+            "too_many_dec_error" : "This feature is not supported because there are too many documents.",
+            "application_not_found" : "Application not found"
 }

+ 15 - 1
language/ko-KR.json

@@ -243,6 +243,8 @@
     "user_head": "사용자 <HEAD>",
     "agreement": "동의",
     "stop": "중지",
+    "application_submitted": "회원가입 신청 완료",
+    "waiting_for_approval": "회원가입 신청이 정상적으로 접수됐습니다. 관리자의 승인을 기다려주세요.",
     "ie_no_data_required": "이 기능을 수행하기 위해 필요한 데이터가 제공되지 않았습니다.",
     "port": "포트",
     "reload": "새로고침",
@@ -310,10 +312,22 @@
     "sqlite_only": "SQLite만",
     "off": "끄기",
     "slow_edit": "편집 속도 제한 시간",
+    "requires_approval" : "가입시 승인필요",
+    "approval_question": "회원가입 질문",
     "public_key": "공개 키",
     "fast_edit_error": "편집 속도가 너무 빠릅니다. 제한 (초) : ",
     "main_acl_setting": "기본 ACL 설정",
     "edit_req_acl": "편집 요청 ACL",
+    "application_list": "가입신청 목록",
+    "application_time": "가입신청 일시",
+    "answer": "답변",
+    "approve": "승인",
+    "decline": "거절",
+    "approve_or_decline": "승인 및 거절",
     "history_add" : "역사 추가",
-    "too_many_dec_error" : "문서 수가 너무 많아서 지원하지 않는 기능 입니다."
+    "too_many_dec_error" : "문서 수가 너무 많아서 지원하지 않는 기능 입니다.",
+    "approval_question_visible_only_when_approval_on" : "회원가입 질문은 가입시 승인필요 설정이 활성화됐을때만 보여집니다.",
+    "no_applications_now" : "회원가입 신청이 없습니다.",
+    "application_not_found" : "존재하지 않는 회원가입 신청입니다.",
+    "approval_requirement_disabled": "현재 가입시 승인필요 설정이 비활성화되어있습니다. 필요시 설정에서 활성화할 수 있습니다."
 }

+ 10 - 0
route/application_submitted.py

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

+ 86 - 0
route/applications.py

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

+ 20 - 1
route/give_user_check.py

@@ -18,6 +18,25 @@ def give_user_check_2(conn, name):
     else:
         sql_num = 0
 
+    approval_question_div = ''
+    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]:
+            approval_question = approval_question[0][0]
+            approval_question_div = '''<table>
+            <thead>
+            <tr><td colspan="2">회원가입 질문</td></tr>
+            </thead>
+            <tbody>
+            <tr><td>질문</td><td>''' + approval_question + '''
+            '''
+            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]:
+                approval_question_div += '<tr><td>답변</td><td>' + approval_question_answer[0][0] + '</td></tr>'
+            approval_question_div += '</tbody></table><br>'
+
     if flask.request.args.get('plus', None):
         end_check = 1
 
@@ -46,7 +65,7 @@ def give_user_check_2(conn, name):
         else:
             div = '<a href="/check/' + url_pas(name) + '">(' + name + ')</a> <a href="/check/' + url_pas(flask.request.args.get('plus', None)) + '">(' + flask.request.args.get('plus', None) + ')</a><hr class=\"main_hr\">'
 
-        div +=  '''
+        div +=  approval_question_div + '''
                 <table id="main_table_set">
                     <tbody>
                         <tr>

+ 32 - 6
route/login_check_key.py

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

+ 41 - 1
route/login_register.py

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

+ 21 - 5
route/setting.py

@@ -25,6 +25,8 @@ def setting_2(conn, num):
             x += 1
             li_data += '<li><a href="/setting/' + str(x) + '">' + li + '</a></li>'
 
+        li_data += '<li><a href="/applications">' + load_lang('application_list') + '</a></li>'
+
         return easy_minify(flask.render_template(skin_check(),
             imp = [load_lang('setting'), wiki_set(), custom(), other2([0, 0])],
             data = '<h2>' + load_lang('list') + '</h2><ul>' + li_data + '</ul>',
@@ -47,7 +49,9 @@ def setting_2(conn, num):
             13 : 'email_have',
             15 : 'encode',
             16 : 'host',
-            19 : 'slow_edit'
+            19 : 'slow_edit',
+            20 : 'requires_approval',
+            21 : 'approval_question'
         }
         n_list = {
             0 : 'Wiki',
@@ -65,7 +69,9 @@ def setting_2(conn, num):
             13 : '',
             15 : 'sha3',
             16 : '0.0.0.0',
-            19 : '0'
+            19 : '0',
+            20 : '',
+            21 : ''
         }
 
         if flask.request.method == 'POST':
@@ -103,14 +109,16 @@ def setting_2(conn, num):
                 else:
                     acl_div[0] += '<option value="' + acl_data + '">' + acl_data + '</option>'
 
-            check_box_div = ['', '', '']
-            for i in range(0, 3):
+            check_box_div = ['', '', '', '']
+            for i in range(0, 4):
                 if i == 0:
                     acl_num = 7
                 elif i == 1:
                     acl_num = 8
-                else:
+                elif i == 2:
                     acl_num = 13
+                else:
+                    acl_num = 20
 
                 if d_list[acl_num]:
                     check_box_div[i] = 'checked="checked"'
@@ -161,6 +169,8 @@ def setting_2(conn, num):
                         <hr class=\"main_hr\">
                         <input type="checkbox" name="email_have" ''' + check_box_div[2] + '''> ''' + load_lang('email_required') + ' <a href="/setting/6">(' + load_lang('google_imap_required') + ''')</a>
                         <hr class=\"main_hr\">
+                        <input type="checkbox" name="requires_approval" ''' + check_box_div[3] + '''> ''' + load_lang('requires_approval') + '''
+                        <hr class=\"main_hr\">
                         <span>''' + load_lang('wiki_host') + '''</span>
                         <hr class=\"main_hr\">
                         <input type="text" name="host" value="''' + html.escape(d_list[16]) + '''">
@@ -185,6 +195,12 @@ def setting_2(conn, num):
                         <hr class=\"main_hr\">
                         <input name="''' + i_list[19] + '''" value="''' + html.escape(d_list[19]) + '''">
                         <hr class=\"main_hr\">
+                        <span>''' + load_lang('approval_question') + '''</span>
+                        <hr class=\"main_hr\">
+                        <input name="''' + i_list[21] + '''" value="''' + html.escape(d_list[21]) + '''">
+                        <hr class=\"main_hr\">
+                        <span>''' + load_lang('approval_question_visible_only_when_approval_on') + '''
+                        <hr class=\"main_hr\">
                         <button id="save" type="submit">''' + load_lang('save') + '''</button>
                     </form>
                 ''',

+ 2 - 0
route/tool/func.py

@@ -1139,6 +1139,8 @@ def re_error(data):
                 data = load_lang('fast_edit_error') + slow_data[0][0]
             elif num == 25:
                 data = load_lang('too_many_dec_error')
+            elif num == 26:
+                data = load_lang('application_not_found')
             else:
                 data = '???'