mirror of
https://github.com/aaronleetw/Attendance.git
synced 2024-11-14 19:11:39 -08:00
Add chgPassword AND mkusr with individual acc
This commit is contained in:
parent
fc9a1701c8
commit
3f345d55d3
10 changed files with 553 additions and 63 deletions
163
app.py
163
app.py
|
@ -24,6 +24,7 @@ config = {
|
|||
"measurementId": os.environ.get('measurementId'),
|
||||
}
|
||||
firebase = pyrebase.initialize_app(config)
|
||||
db = firebase.database()
|
||||
auth = firebase.auth()
|
||||
tz = pytz.timezone('Asia/Taipei')
|
||||
|
||||
|
@ -52,22 +53,38 @@ def index():
|
|||
if request.method == 'GET':
|
||||
if check_login_status():
|
||||
return render_template('login.html')
|
||||
return redirect('/manage')
|
||||
return redirect('/select')
|
||||
elif request.method == 'POST':
|
||||
email = request.form['username'] + "@group-attendance.fhjh.tp.edu.tw"
|
||||
email = request.form['username']
|
||||
if check_login_status():
|
||||
try:
|
||||
if (verify_recaptcha("")):
|
||||
user = auth.sign_in_with_email_and_password(
|
||||
email, request.form['password'])
|
||||
print("Login SUCC:", email, flush=True)
|
||||
usrData = db.child("Users").child(user['localId']).child("permission").get(
|
||||
user['idToken']).val()
|
||||
if (usrData == 'realPerson'):
|
||||
print("RealPerson Login SUCC:", email, flush=True)
|
||||
session['is_logged_in'] = True
|
||||
session['email'] = user['email']
|
||||
session['uid'] = user['localId']
|
||||
session['token'] = user['idToken']
|
||||
session['refreshToken'] = user['refreshToken']
|
||||
session['loginTime'] = datetime.now(tz)
|
||||
return redirect('/select')
|
||||
if (usrData == 'admin'):
|
||||
print("Admin Login SUCC:", email, flush=True)
|
||||
session['subuser_type'] = 'admin'
|
||||
session['is_logged_in'] = True
|
||||
session['email'] = user['email']
|
||||
session['uid'] = user['localId']
|
||||
session['token'] = user['idToken']
|
||||
session['refreshToken'] = user['refreshToken']
|
||||
session['loginTime'] = datetime.now(tz)
|
||||
session['showUpload'] = db.child("Users").child(
|
||||
session['uid']).child("showUpload").get(session['token']).val()
|
||||
return redirect('/manage')
|
||||
raise Exception("not real person or admin")
|
||||
else:
|
||||
print("ReC Error:", email, flush=True)
|
||||
flash(
|
||||
|
@ -79,7 +96,147 @@ def index():
|
|||
'帳號或密碼錯誤,請重新輸入<br>Incorrect username or password')
|
||||
return redirect('/')
|
||||
else:
|
||||
return redirect('/select')
|
||||
|
||||
|
||||
@app.route('/select', methods=['GET', 'POST'])
|
||||
def selSubUser():
|
||||
if check_login_status():
|
||||
print(session)
|
||||
session.clear()
|
||||
flash("Timeout. 遇時,請重新登入")
|
||||
return redirect('/')
|
||||
if 'subuser_type' in session and session['subuser_type'] == 'admin':
|
||||
return redirect('/manage')
|
||||
if request.method == 'GET':
|
||||
usrData = db.child("Users").child(session['uid']).get(
|
||||
session['token']).val()
|
||||
session['subuser_type'] = ''
|
||||
return render_template('selSubUser.html', data=usrData['accounts'], name=usrData['name'])
|
||||
else:
|
||||
data = request.form['subuser_sel'].split('^')
|
||||
try:
|
||||
if (verify_recaptcha("")):
|
||||
if (data[0] == 'homeroom'):
|
||||
session['homeroom'] = data[1] + '^' + data[2]
|
||||
session['subuser_type'] = 'homeroom'
|
||||
elif (data[0] == 'group'):
|
||||
session['category'] = data[1]
|
||||
session['class'] = data[2]
|
||||
session['subuser_type'] = 'group'
|
||||
return redirect('/manage')
|
||||
else:
|
||||
print("ReC Error:", data, flush=True)
|
||||
flash(
|
||||
'reCAPTCHA 錯誤,請稍後再試一次<br>reCAPTCHA Failed. Please try again later.')
|
||||
return redirect('/select')
|
||||
except Exception as e:
|
||||
print("Error:", data, str(e), flush=True)
|
||||
flash(str(e))
|
||||
return redirect('/select')
|
||||
|
||||
|
||||
@app.route('/chgPassword', methods=['POST', 'GET'])
|
||||
def chgPassword():
|
||||
data = {}
|
||||
if request.method == 'GET':
|
||||
if not check_login_status():
|
||||
return render_template('chgPassword.html')
|
||||
else:
|
||||
return abort(404)
|
||||
elif request.method == 'POST':
|
||||
oldEmail = session['email']
|
||||
delUser = False
|
||||
if not check_login_status():
|
||||
try:
|
||||
if (verify_recaptcha("")):
|
||||
oldUsr = auth.sign_in_with_email_and_password(
|
||||
oldEmail, request.form['password'])
|
||||
print("chgPwd oldUser:", oldEmail, flush=True)
|
||||
old = {}
|
||||
old['uid'] = oldUsr['localId']
|
||||
old['token'] = oldUsr['idToken']
|
||||
data = db.child("Users").child(
|
||||
oldUsr['localId']).get(oldUsr['idToken']).val()
|
||||
print("data:", data, flush=True)
|
||||
|
||||
auth.delete_user_account(oldUsr['idToken'])
|
||||
delUser = True
|
||||
|
||||
newUsr = auth.create_user_with_email_and_password(
|
||||
request.form['new_username'], request.form['new_password'])
|
||||
db.child("Users").child(newUsr['localId']).set(
|
||||
data, newUsr['idToken'])
|
||||
session.clear()
|
||||
flash(
|
||||
'修改密碼成功,請重新登入<br>Password changed successfully. Please login again.')
|
||||
return redirect('/')
|
||||
else:
|
||||
print("ReC Error:", oldEmail, flush=True)
|
||||
flash(
|
||||
'reCAPTCHA 錯誤,請稍後再試一次<br>reCAPTCHA Failed. Please try again later.')
|
||||
return redirect('/chgPassword')
|
||||
except Exception as e:
|
||||
if delUser:
|
||||
try:
|
||||
usr = auth.create_user_with_email_and_password(
|
||||
oldEmail, request.form['password'])
|
||||
db.child("Users").child(usr['localId']).set(
|
||||
data, usr['idToken'])
|
||||
except:
|
||||
pass
|
||||
print("Error:", oldEmail, str(e), flush=True)
|
||||
flash(str(e))
|
||||
return redirect('/chgPassword')
|
||||
|
||||
|
||||
@app.route('/iforgot', methods=['GET', 'POST'])
|
||||
def iforgot():
|
||||
if request.method == 'GET':
|
||||
return render_template('iforgot.html')
|
||||
elif request.method == 'POST':
|
||||
email = request.form['username']
|
||||
try:
|
||||
if (verify_recaptcha("")):
|
||||
auth.send_password_reset_email(email)
|
||||
print("iforgot email sent:", email, flush=True)
|
||||
flash(
|
||||
'重置密碼信件已寄出,請至信箱收取<br>Password reset email has been sent to your email. Please check your email.')
|
||||
return redirect('/')
|
||||
else:
|
||||
print("ReC Error:", email, flush=True)
|
||||
flash(
|
||||
'reCAPTCHA 錯誤,請稍後再試一次<br>reCAPTCHA Failed. Please try again later.')
|
||||
return redirect('/iforgot')
|
||||
except Exception as e:
|
||||
print("Error:", email, str(e), flush=True)
|
||||
flash(str(e))
|
||||
return redirect('/iforgot')
|
||||
|
||||
|
||||
@app.route('/resetPassword', methods=['GET', 'POST'])
|
||||
def resetPassword():
|
||||
if request.method == 'GET':
|
||||
session['oobCode'] = request.args.get('oobCode')
|
||||
return render_template('verifiedChgPassword.html')
|
||||
else:
|
||||
try:
|
||||
if (verify_recaptcha("")):
|
||||
auth.verify_password_reset_code(
|
||||
session['oobCode'], request.form['password'])
|
||||
print("resetPassword success:", flush=True)
|
||||
session.clear()
|
||||
flash('重置密碼成功,請重新登入<br>Password reset success. Please login again.')
|
||||
return redirect('/')
|
||||
else:
|
||||
print("ReC Error:", flush=True)
|
||||
flash(
|
||||
'reCAPTCHA 錯誤,請稍後再試一次<br>reCAPTCHA Failed. Please try again later.')
|
||||
return redirect('/resetPassword')
|
||||
except Exception as e:
|
||||
print("Error:", str(e), flush=True)
|
||||
flash(str(e))
|
||||
return redirect('/resetPassword')
|
||||
|
||||
|
||||
@ app.route('/logout', methods=['GET'])
|
||||
|
|
36
manage.py
36
manage.py
|
@ -51,8 +51,7 @@ def manageProcess(fCommand, fData):
|
|||
db.child("Users").child(
|
||||
session['uid']).child("permission").get(session['token']).val()
|
||||
# end bug fix
|
||||
pl = db.child("Users").child(
|
||||
session['uid']).child("permission").get(session['token']).val()
|
||||
pl = session['subuser_type']
|
||||
if pl == 'admin':
|
||||
homerooms = db.child("Homerooms").get(session['token']).val()
|
||||
currRoom = []
|
||||
|
@ -80,20 +79,14 @@ def manageProcess(fCommand, fData):
|
|||
break
|
||||
return render_template('admin.html', homerooms=homerooms, absData=absData,
|
||||
homeroomCode=currRoom, homeroomData=homeroomData, currDate=currDate, periods=['m', '1', '2', '3', '4',
|
||||
'n', '5', '6', '7', '8', '9'], showUpload=db.child("Users").child(
|
||||
session['uid']).child("showUpload").get(session['token']).val())
|
||||
'n', '5', '6', '7', '8', '9'], showUpload=session['showUpload'])
|
||||
elif pl == 'group':
|
||||
classes = db.child("Users").child(
|
||||
session['uid']).child("class").get(session['token']).val()
|
||||
cclass = {}
|
||||
cateData = {}
|
||||
for i in classes:
|
||||
cateData = db.child("Classes").child(
|
||||
"GP_Class").child(i).get(session['token']).val()
|
||||
"GP_Class").child(session['category']).get(session['token']).val()
|
||||
cclass = {
|
||||
"name": cateData['Class'][classes[i]]['name'],
|
||||
"category": i,
|
||||
"class_id": classes[i]
|
||||
"name": cateData['Class'][session['class']]['name'],
|
||||
"category": session['category'],
|
||||
"class_id": session['class']
|
||||
}
|
||||
homerooms = cateData['Homerooms']
|
||||
currDate = ""
|
||||
|
@ -175,8 +168,7 @@ def manageProcess(fCommand, fData):
|
|||
}
|
||||
return render_template('group_teach.html', cclass=cclass, absData=absData, dow=dow, currDate=currDate, tmpAbsData=tmpAbsData, confirmed=confirmed)
|
||||
elif pl == 'homeroom':
|
||||
homeroom = db.child("Users").child(
|
||||
session['uid']).child("homeroom").get(session['token']).val().split('^')
|
||||
homeroom = session['homeroom'].split('^')
|
||||
homeroomData = db.child("Homerooms").child(homeroom[0]).child(
|
||||
homeroom[1]).get(session['token']).val()
|
||||
times = OrderedDict({
|
||||
|
@ -241,17 +233,13 @@ def manage_admin():
|
|||
def group_teach_publish():
|
||||
if (check_login_status()):
|
||||
return redirect('/logout')
|
||||
classes = db.child("Users").child(
|
||||
session['uid']).child("class").get(session['token']).val()
|
||||
cclass = {}
|
||||
for i in classes:
|
||||
cclass = {
|
||||
"name": db.child("Classes").child("GP_Class").child(i).child(
|
||||
"Class").child(classes[i]).child("name").get(session['token']).val(),
|
||||
"category": i,
|
||||
"class_id": classes[i],
|
||||
"name": db.child("Classes").child("GP_Class").child(session['category']).child(
|
||||
"Class").child(session['class']).child("name").get(session['token']).val(),
|
||||
"category": session['category'],
|
||||
"class_id": session['class'],
|
||||
"homerooms": db.child("Classes").child(
|
||||
"GP_Class").child(i).child("Homerooms").get(session['token']).val()
|
||||
"GP_Class").child(session['category']).child("Homerooms").get(session['token']).val()
|
||||
}
|
||||
date = request.form['date']
|
||||
period = request.form['period']
|
||||
|
|
104
templates/chgPassword.html
Normal file
104
templates/chgPassword.html
Normal file
|
@ -0,0 +1,104 @@
|
|||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Attendance 點名系統 (β)</title>
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.1/dist/css/bootstrap.min.css" rel="stylesheet"
|
||||
integrity="sha384-F3w7mX95PdgyTmZZMECAngseQB83DfGTowi0iMjiWaeVhAn4FJkqJByhZMI3AhiU" crossorigin="anonymous">
|
||||
<link rel="stylesheet" href="/static/allpages.css">
|
||||
<link rel="stylesheet" href="/static/login.css">
|
||||
<link rel="shortcut icon" type="image/x-icon" href="/static/favicon.ico" />
|
||||
<!-- Global site tag (gtag.js) - Google Analytics -->
|
||||
<script async src="https://www.googletagmanager.com/gtag/js?id=G-H6D61RSBHR"></script>
|
||||
<script>
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
function gtag() { dataLayer.push(arguments); }
|
||||
gtag('js', new Date());
|
||||
|
||||
gtag('config', 'G-H6D61RSBHR');
|
||||
</script>
|
||||
<style>
|
||||
.form-group {
|
||||
margin-bottom: 30px !important;
|
||||
}
|
||||
</style>
|
||||
<!-- <script src="https://www.google.com/recaptcha/api.js"></script> -->
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="showTime"><span id="showTime"></span></div>
|
||||
<div class="container">
|
||||
<h1 class="margin-top margin-bottom">Attendance 點名系統 (β) | Change Password 更改密碼</h1>
|
||||
<div class="row">
|
||||
<div class="col"></div>
|
||||
<div class="col-md-5">
|
||||
<form action="/chgPassword" id="loginForm" method="post">
|
||||
<div class="form-group row" style="margin-bottom: 10px;">
|
||||
<div class="col-3 center"><label for="password" style="font-size: 19px">Old Password 舊密碼:
|
||||
</label>
|
||||
</div>
|
||||
<div class="col-9 center-input"><input type="password" class="form-control" name="password"
|
||||
id="password" required></div>
|
||||
</div>
|
||||
|
||||
<div class="form-group row" style="margin-bottom: 10px;">
|
||||
<div class="col-3 center"><label for="password" style="font-size: 19px">New Username 新帳號:
|
||||
</label>
|
||||
</div>
|
||||
<div class="col-9 center-input"><input type="email" class="form-control" name="new_username"
|
||||
id="new_username" required></div>
|
||||
</div>
|
||||
<div class="form-group row" style="margin-bottom: 10px;">
|
||||
<div class="col-3 center"><label for="password" style="font-size: 19px">New Password 新密碼:
|
||||
</label>
|
||||
</div>
|
||||
<div class="col-9 center-input"><input type="password" class="form-control" name="new_password"
|
||||
id="new_password" required></div>
|
||||
</div>
|
||||
<button class="btn btn-danger btn-block g-recaptcha" onclick="loadingAnimation()">Change Password
|
||||
更改密碼</button>
|
||||
<a href="/"><button type="button" class="btn btn-primary btn-block g-recaptcha"
|
||||
onclick="loadingAnimation()">Go back 回上一頁</button></a>
|
||||
</form>
|
||||
<div class="disclaimer" hidden="hidden">
|
||||
This site is protected by reCAPTCHA and the Google
|
||||
<a target="_blank" href="https://policies.google.com/privacy">Privacy Policy</a> and
|
||||
<a target="_blank" href="https://policies.google.com/terms">Terms of Service</a> apply.
|
||||
</div>
|
||||
{% with messages = get_flashed_messages() %}
|
||||
{% if messages %}
|
||||
<div class="alert alert-danger" role="alert">
|
||||
{% for message in messages %}
|
||||
{% autoescape false %}{{message}}{% endautoescape %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
</div>
|
||||
<div class="col"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="loading" style="text-align:center; width:100%; display:none;"><img src="/static/loading.gif" alt=""
|
||||
style="height:100%;" />
|
||||
</div>
|
||||
{% include 'footer.html' %}
|
||||
<script type=" text/javascript" src="/static/jquery.min.js"></script>
|
||||
<script>
|
||||
function validateEmail(email) {
|
||||
const emailRegEx = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
|
||||
function loadingAnimation() {
|
||||
$('#loginForm').submit();
|
||||
if ($("#username").val() == "" || $("#password").val() == "" || $("#new_username").val() == "" || $("#new_password").val() == "" ||
|
||||
!emailRegEx.test($("#username").val().toLowerCase()) || !emailRegEx.test($("#new_username").val().toLowerCase())) {
|
||||
return;
|
||||
}
|
||||
$('.container').hide();
|
||||
$('#loading').show();
|
||||
}
|
||||
</script>
|
||||
<script src="/static/time.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -29,6 +29,7 @@
|
|||
<h2 class="margin-top">{{cclass['category']}}: {{cclass['class_id']}}: {{cclass['name']}}</h2>
|
||||
<h2>[{{currDate}}]</h2>
|
||||
<a href="/logout"><button class="btn btn-primary margin-top logout">Logout 登出</button></a>
|
||||
<a href="/select"><button class="btn btn-primary margin-top logout">選擇其他帳號 Choose Subuser</button></a>
|
||||
<form action="/manage/date" id="dateSelForm" method="post">
|
||||
<select name="date" id="date" class="form-select logout" onchange="chgDate(this);">
|
||||
{% for date in tmpAbsData %}
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
<h2 class="margin-top">{{homeroomCode[0]}}{{homeroomCode[1]}}</h2>
|
||||
<h2>[{{currDate}}]</h2>
|
||||
<a href="/logout"><button class="btn btn-primary logout margin-top">Logout 登出</button></a>
|
||||
<a href="/select"><button class="btn btn-primary margin-top logout">選擇其他帳號 Choose Subuser</button></a>
|
||||
<form action="/manage/date" id="dateSelForm" method="post">
|
||||
<select name="date" id="date" class="form-select logout" onchange="chgDate();">
|
||||
{% for date in absData %}
|
||||
|
|
73
templates/iforgot.html
Normal file
73
templates/iforgot.html
Normal file
|
@ -0,0 +1,73 @@
|
|||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Attendance 點名系統 (β)</title>
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.1/dist/css/bootstrap.min.css" rel="stylesheet"
|
||||
integrity="sha384-F3w7mX95PdgyTmZZMECAngseQB83DfGTowi0iMjiWaeVhAn4FJkqJByhZMI3AhiU" crossorigin="anonymous">
|
||||
<link rel="stylesheet" href="/static/allpages.css">
|
||||
<link rel="stylesheet" href="/static/login.css">
|
||||
<link rel="shortcut icon" type="image/x-icon" href="/static/favicon.ico" />
|
||||
<!-- Global site tag (gtag.js) - Google Analytics -->
|
||||
<script async src="https://www.googletagmanager.com/gtag/js?id=G-H6D61RSBHR"></script>
|
||||
<script>
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
function gtag() { dataLayer.push(arguments); }
|
||||
gtag('js', new Date());
|
||||
|
||||
gtag('config', 'G-H6D61RSBHR');
|
||||
</script>
|
||||
<!-- <script src="https://www.google.com/recaptcha/api.js"></script> -->
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="showTime"><span id="showTime"></span></div>
|
||||
<div class="container">
|
||||
<h1 class="margin-top margin-bottom">Attendance 點名系統 (β) | Reset Password 忘記密碼</h1>
|
||||
<div class="row">
|
||||
<div class="col"></div>
|
||||
<div class="col-md-5">
|
||||
<form action="/iforgot" id="forgotPassword_sel" method="post">
|
||||
<div class="form-group row" style="margin-bottom: 10px;">
|
||||
<div class="col-3 center"><label for="username" style="font-size: 19px">Username 帳號: </label>
|
||||
</div>
|
||||
<div class="col-9 center-input"><input type="text" class="form-control" name="username"
|
||||
id="username"></div>
|
||||
</div>
|
||||
<button class="btn btn-warning btn-block g-recaptcha" onclick="loadingAnimation()">Confirm
|
||||
確認</button>
|
||||
</form>
|
||||
<p>This will send an email to the email address to verify your identity.<br>
|
||||
這會傳送一個郵件到指定的信箱,以驗證您的身份
|
||||
</p>
|
||||
{% with messages = get_flashed_messages() %}
|
||||
{% if messages %}
|
||||
<div class="alert alert-danger" role="alert">
|
||||
{% for message in messages %}
|
||||
{% autoescape false %}{{message}}{% endautoescape %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
</div>
|
||||
<div class="col"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="loading" style="text-align:center; width:100%; display:none;"><img src="/static/loading.gif" alt=""
|
||||
style="height:100%;" />
|
||||
</div>
|
||||
{% include 'footer.html' %}
|
||||
<script type=" text/javascript" src="/static/jquery.min.js"></script>
|
||||
<script>
|
||||
function loadingAnimation() {
|
||||
$('#forgotPassword_sel').submit();
|
||||
$('.container').hide();
|
||||
$('#loading').show();
|
||||
}
|
||||
</script>
|
||||
<script src="/static/time.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -45,6 +45,7 @@
|
|||
<button class="btn btn-primary btn-block g-recaptcha" onclick="loadingAnimation()">Login
|
||||
登入</button>
|
||||
</form>
|
||||
<a href="/iforgot">Forgot Password 忘記密碼</a>
|
||||
<div class="disclaimer" hidden="hidden">
|
||||
This site is protected by reCAPTCHA and the Google
|
||||
<a target="_blank" href="https://policies.google.com/privacy">Privacy Policy</a> and
|
||||
|
@ -52,7 +53,7 @@
|
|||
</div>
|
||||
{% with messages = get_flashed_messages() %}
|
||||
{% if messages %}
|
||||
<div class="alert alert-danger" role="alert">
|
||||
<div class="alert alert-danger margin-top" role="alert">
|
||||
{% for message in messages %}
|
||||
{% autoescape false %}{{message}}{% endautoescape %}
|
||||
{% endfor %}
|
||||
|
|
68
templates/selSubUser.html
Normal file
68
templates/selSubUser.html
Normal file
|
@ -0,0 +1,68 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Select Subuser 選擇子帳號</title>
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.1/dist/css/bootstrap.min.css" rel="stylesheet"
|
||||
integrity="sha384-F3w7mX95PdgyTmZZMECAngseQB83DfGTowi0iMjiWaeVhAn4FJkqJByhZMI3AhiU" crossorigin="anonymous">
|
||||
<link rel="stylesheet" href="/static/allpages.css">
|
||||
<link rel="stylesheet" href="/static/homeroom.css">
|
||||
<link rel="shortcut icon" type="image/x-icon" href="/static/favicon.ico" />
|
||||
<!-- Global site tag (gtag.js) - Google Analytics -->
|
||||
<script async src="https://www.googletagmanager.com/gtag/js?id=G-H6D61RSBHR"></script>
|
||||
<script>
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
function gtag() { dataLayer.push(arguments); }
|
||||
gtag('js', new Date());
|
||||
|
||||
gtag('config', 'G-H6D61RSBHR');
|
||||
</script>
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="showTime"><span id="showTime"></span></div>
|
||||
<div class="container">
|
||||
<h1 class="margin-top">Select Subuser 選擇子帳號</h1>
|
||||
<h2 class="margin-top">{{name}}</h2>
|
||||
<a href="/logout"><button class="btn btn-primary logout margin-top">Logout 登出</button></a>
|
||||
<form action="/select" id="subuser_form_sel" method="post">
|
||||
<select name="subuser_sel" id="subuser_sel" class="form-select logout" onchange="loadingAnimation();"
|
||||
required>
|
||||
<option value="" selected>Please select</option>
|
||||
{% for key in data %}
|
||||
{% if data[key]['type'] == 'homeroom' %}
|
||||
<option value="homeroom^{{data[key]['homeroom']}}">Homeroom: {{data[key]['homeroom']}}</option>
|
||||
{% else %}
|
||||
{% for i in data[key] %}
|
||||
{% if i == 'type' %}
|
||||
{% else %}
|
||||
<option value="group^{{i}}^{{data[key][i]}}">GP: {{i}}: {{data[key][i]}}</option>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</select>
|
||||
</form>
|
||||
</div>
|
||||
<div id="loading" style="text-align:center; width:100%; display:none;"><img src="/static/loading.gif" alt=""
|
||||
style="height:100%;" />
|
||||
</div>
|
||||
{% include 'footer.html' %}
|
||||
<script type=" text/javascript" src="/static/jquery.min.js"></script>
|
||||
<script>
|
||||
function loadingAnimation() {
|
||||
if ($('#subuser_form_sel').val == '')
|
||||
return;
|
||||
$('#subuser_form_sel').submit();
|
||||
$('.container').hide();
|
||||
$('#loading').show();
|
||||
}
|
||||
</script>
|
||||
<script src="/static/time.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
71
templates/verifiedChgPassword.html
Normal file
71
templates/verifiedChgPassword.html
Normal file
|
@ -0,0 +1,71 @@
|
|||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Attendance 點名系統 (β)</title>
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.1/dist/css/bootstrap.min.css" rel="stylesheet"
|
||||
integrity="sha384-F3w7mX95PdgyTmZZMECAngseQB83DfGTowi0iMjiWaeVhAn4FJkqJByhZMI3AhiU" crossorigin="anonymous">
|
||||
<link rel="stylesheet" href="/static/allpages.css">
|
||||
<link rel="stylesheet" href="/static/login.css">
|
||||
<link rel="shortcut icon" type="image/x-icon" href="/static/favicon.ico" />
|
||||
<!-- Global site tag (gtag.js) - Google Analytics -->
|
||||
<script async src="https://www.googletagmanager.com/gtag/js?id=G-H6D61RSBHR"></script>
|
||||
<script>
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
function gtag() { dataLayer.push(arguments); }
|
||||
gtag('js', new Date());
|
||||
|
||||
gtag('config', 'G-H6D61RSBHR');
|
||||
</script>
|
||||
<!-- <script src="https://www.google.com/recaptcha/api.js"></script> -->
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="showTime"><span id="showTime"></span></div>
|
||||
<div class="container">
|
||||
<h1 class="margin-top margin-bottom">Attendance 點名系統 (β) | Reset Password 忘記密碼</h1>
|
||||
<div class="row">
|
||||
<div class="col"></div>
|
||||
<div class="col-md-5">
|
||||
<form action="/resetPassword" id="password_form" method="post">
|
||||
<div class="form-group row" style="margin-bottom: 10px;">
|
||||
<div class="col-3 center"><label for="password" style="font-size: 19px">New Password 新密碼:
|
||||
</label>
|
||||
</div>
|
||||
<div class="col-9 center-input"><input type="password" class="form-control" name="password"
|
||||
id="password"></div>
|
||||
</div>
|
||||
<button class="btn btn-warning btn-block g-recaptcha" onclick="loadingAnimation()">Confirm
|
||||
確認</button>
|
||||
</form>
|
||||
{% with messages = get_flashed_messages() %}
|
||||
{% if messages %}
|
||||
<div class="alert alert-danger" role="alert">
|
||||
{% for message in messages %}
|
||||
{% autoescape false %}{{message}}{% endautoescape %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
</div>
|
||||
<div class="col"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="loading" style="text-align:center; width:100%; display:none;"><img src="/static/loading.gif" alt=""
|
||||
style="height:100%;" />
|
||||
</div>
|
||||
{% include 'footer.html' %}
|
||||
<script type=" text/javascript" src="/static/jquery.min.js"></script>
|
||||
<script>
|
||||
function loadingAnimation() {
|
||||
$('#password_form').submit();
|
||||
$('.container').hide();
|
||||
$('#loading').show();
|
||||
}
|
||||
</script>
|
||||
<script src="/static/time.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
64
upload.py
64
upload.py
|
@ -6,6 +6,7 @@ import csv
|
|||
import os
|
||||
import pandas as pd
|
||||
from dotenv import load_dotenv
|
||||
from random import randint
|
||||
load_dotenv()
|
||||
|
||||
upload = Blueprint('upload', __name__)
|
||||
|
@ -36,6 +37,35 @@ def check_permission():
|
|||
db.child("Users").child(session['uid']).child("showUpload").get(session['token']).val() == '1')
|
||||
|
||||
|
||||
@upload.route('/upload/users', methods=['GET', 'POST'])
|
||||
def upload_users():
|
||||
if ((not check_login_status()) and check_permission()):
|
||||
if request.method == 'GET':
|
||||
return render_template('uploadcsv.html', title="All Indiviual Users", url="/upload/users")
|
||||
elif request.method == 'POST':
|
||||
try:
|
||||
csv_file = request.files['csv']
|
||||
filepath = os.path.join('./temp', csv_file.filename)
|
||||
csv_file.save(filepath)
|
||||
with open(filepath) as file:
|
||||
csv_dict = csv.DictReader(file)
|
||||
for row in csv_dict:
|
||||
user = auth.create_user_with_email_and_password(
|
||||
row['username'] + "@group-attendance.fhjh.tp.edu.tw", row['password'])
|
||||
db.child("Users").child(user['localId']).set({
|
||||
'permission': 'realPerson',
|
||||
'name': row['name'],
|
||||
'origUsername': row['username'],
|
||||
}, session['token'])
|
||||
os.remove(filepath)
|
||||
except Exception as e:
|
||||
os.remove(filepath)
|
||||
return "Error. Please try again\n("+str(e)+")"
|
||||
return "Successfully uploaded users"
|
||||
else:
|
||||
return redirect('/logout')
|
||||
|
||||
|
||||
@upload.route('/upload/1', methods=['GET', 'POST'])
|
||||
def upload_homeroom():
|
||||
if ((not check_login_status()) and check_permission()):
|
||||
|
@ -49,19 +79,18 @@ def upload_homeroom():
|
|||
csv_file = request.files['csv']
|
||||
filepath = os.path.join('./temp', csv_file.filename)
|
||||
csv_file.save(filepath)
|
||||
allUsers = db.child("Users").get(session['token']).val()
|
||||
with open(filepath) as file:
|
||||
csv_dict = csv.DictReader(file)
|
||||
for row in csv_dict:
|
||||
if row['number'] == 'password':
|
||||
auth.create_user_with_email_and_password(
|
||||
gradec + classc + "@group-attendance.fhjh.tp.edu.tw", row['name'])
|
||||
user = auth.sign_in_with_email_and_password(
|
||||
gradec + classc + "@group-attendance.fhjh.tp.edu.tw", row['name'])
|
||||
db.child("Users").child(user['localId']).update({
|
||||
"permission": 'homeroom',
|
||||
"username": gradec + classc,
|
||||
"homeroom": gradec + '^' + classc
|
||||
})
|
||||
if row['number'] == 'teacher':
|
||||
for key in allUsers:
|
||||
if (allUsers[key]['origUsername'] == row['name']):
|
||||
db.child("Users").child(key).child("accounts").child("homeroom^"+gradec+classc+'^'+randint(10000)).update({
|
||||
"homeroom": gradec + '^' + classc,
|
||||
"type": 'homeroom'
|
||||
}, session['token'])
|
||||
break
|
||||
else:
|
||||
db.child("Homerooms").child(gradec).child(
|
||||
classc).child(row['number']).set(row, session['token'])
|
||||
|
@ -87,6 +116,7 @@ def upload_gp_classes():
|
|||
csv_file.save(filepath)
|
||||
csv_dict = pd.read_csv(filepath)
|
||||
category_cnt = csv_dict.shape[1] - 1
|
||||
allUsers = db.child("Users").get(session['token']).val()
|
||||
for i in range(category_cnt):
|
||||
tmp_csv = csv_dict[csv_dict.columns[i+1]].tolist()
|
||||
for j in range(len(tmp_csv)):
|
||||
|
@ -95,17 +125,13 @@ def upload_gp_classes():
|
|||
if j % 5 == 0:
|
||||
db.child("Classes").child("GP_Class").child(csv_dict.columns[i+1]).child("Class").child(
|
||||
tmp_csv[j]).child("name").set(tmp_csv[j+1] + " : " + tmp_csv[j+2] + " (" + tmp_csv[j+3] + ")", session['token'])
|
||||
auth.create_user_with_email_and_password(
|
||||
tmp_csv[j] + "@group-attendance.fhjh.tp.edu.tw", tmp_csv[j+4])
|
||||
user = auth.sign_in_with_email_and_password(
|
||||
tmp_csv[j] + "@group-attendance.fhjh.tp.edu.tw", tmp_csv[j+4])
|
||||
db.child("Users").child(user['localId']).update({
|
||||
"permission": 'group',
|
||||
"username": tmp_csv[j],
|
||||
"class": {
|
||||
for key in allUsers:
|
||||
if (allUsers[key]['origUsername'] == tmp_csv[j+4]):
|
||||
db.child("Users").child(key).child("accounts").child("GP_Class^"+csv_dict.columns[i+1]+'^'+randint(10000)).update({
|
||||
csv_dict.columns[i+1]: tmp_csv[j],
|
||||
}
|
||||
"type": 'group'
|
||||
}, session['token'])
|
||||
break
|
||||
os.remove(filepath)
|
||||
except Exception as e:
|
||||
os.remove(filepath)
|
||||
|
|
Loading…
Reference in a new issue