Separate py files

This commit is contained in:
Aaron Lee 2021-09-26 21:37:34 +08:00
parent 54b5bfae63
commit 9edc8863c8
8 changed files with 621 additions and 558 deletions

549
app.py
View file

@ -1,16 +1,16 @@
from typing import OrderedDict
from flask import * from flask import *
import pyrebase import pyrebase
from datetime import datetime from datetime import datetime
import pytz import pytz
import csv
import os import os
import pandas as pd
import base64
from dotenv import load_dotenv from dotenv import load_dotenv
import requests import requests
from manage import manage
from upload import upload
load_dotenv() load_dotenv()
app = Flask(__name__) app = Flask(__name__)
app.register_blueprint(manage)
app.register_blueprint(upload)
app.config['SECRET_KEY'] = os.environ.get('SECRET_KEY') app.config['SECRET_KEY'] = os.environ.get('SECRET_KEY')
config = { config = {
@ -24,27 +24,16 @@ config = {
"measurementId": os.environ.get('measurementId'), "measurementId": os.environ.get('measurementId'),
} }
firebase = pyrebase.initialize_app(config) firebase = pyrebase.initialize_app(config)
db = firebase.database()
auth = firebase.auth() auth = firebase.auth()
storage = firebase.storage()
tz = pytz.timezone('Asia/Taipei') tz = pytz.timezone('Asia/Taipei')
def next_item(odic, key):
return list(odic)[list(odic.keys()).index(key) + 1]
def check_login_status(): def check_login_status():
return ('is_logged_in' not in session or return ('is_logged_in' not in session or
session['is_logged_in'] == False or session['is_logged_in'] == False or
(datetime.now(tz) - session['loginTime']).total_seconds() > 3600) (datetime.now(tz) - session['loginTime']).total_seconds() > 3600)
def check_permission():
return (db.child('Users').child(session['uid']).child('permission').get(session['token']).val() == 'admin' and
db.child("Users").child(session['uid']).child("showUpload").get(session['token']).val() == '1')
def verify_recaptcha(response): def verify_recaptcha(response):
data = { data = {
'secret': os.environ.get('RECAPTCHA_SECRET'), 'secret': os.environ.get('RECAPTCHA_SECRET'),
@ -56,186 +45,6 @@ def verify_recaptcha(response):
return r.json()['success'] return r.json()['success']
def removeprefix(s, prefix):
if s.startswith(prefix):
return s[len(prefix):]
return s
def manageProcess(fCommand, fData):
if (check_login_status()):
return redirect('/logout')
# this is to fix a bug where pyrebase doesnt load the first request
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()
if pl == 'admin':
homerooms = db.child("Homerooms").get(session['token']).val()
currRoom = []
if fCommand == "admin":
currRoom = fData[0].split("^")
else:
for i in homerooms:
currRoom.append(i)
for j in homerooms[i]:
currRoom.append(j)
break
break
homeroomData = homerooms[currRoom[0]][currRoom[1]]
absData = homeroomData["Absent"]
homeroomData.pop('Absent')
if 'placeholder' in homeroomData:
homeroomData.pop('placeholder')
currDate = ""
if fCommand != "":
currDate = fData[1]
else:
for i in absData:
currDate = i
if i >= datetime.now(tz).strftime("%Y-%m-%d"):
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())
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()
cclass = {
"name": cateData['Class'][classes[i]]['name'],
"category": i,
"class_id": classes[i]
}
homerooms = cateData['Homerooms']
currDate = ""
confirmed = []
absData = {}
for h in homerooms:
h = h.split('^')
hrData = db.child("Homerooms").child(
h[0]).child(h[1]).get(session['token']).val()
tmpAbsData = hrData['Absent']
hrData.pop('Absent')
if 'placeholder' in hrData:
hrData.pop('placeholder')
periods = []
dow = ""
if currDate == "":
if fCommand == 'date':
currDate = fData
for j in tmpAbsData[currDate]:
if j == "dow":
dow = tmpAbsData[currDate][j]
continue
elif j == "confirm":
confirmed.append([h[0], h[1]])
continue
if (tmpAbsData[currDate][j]['name'] == 'GP' and
tmpAbsData[currDate][j]['teacher'] == cclass['category']):
periods.append(j)
else:
for i in tmpAbsData:
currDate = i
if i >= datetime.now(tz).strftime("%Y-%m-%d"):
tmp = False
for j in tmpAbsData[i]:
if j == "dow":
dow = tmpAbsData[i][j]
continue
elif j == "confirm":
confirmed.append([h[0], h[1]])
continue
if (tmpAbsData[i][j]['name'] == 'GP' and
tmpAbsData[i][j]['teacher'] == cclass['category']):
periods.append(j)
tmp = True
if tmp == True:
break
else:
for j in tmpAbsData[currDate]:
if j == "dow":
dow = tmpAbsData[currDate][j]
continue
elif j == "confirm":
confirmed.append([h[0], h[1]])
continue
if (tmpAbsData[currDate][j]['name'] == 'GP' and
tmpAbsData[currDate][j]['teacher'] == cclass['category']):
periods.append(j)
for p in periods:
if not p in absData:
absData[p] = {}
for p in periods:
if not h[0] in absData[p]:
absData[p][h[0]] = {}
absData[p][h[0]][h[1]] = {}
if 'notes' in tmpAbsData[currDate][p]:
absData[p][h[0]][h[1]
]['notes'] = tmpAbsData[currDate][p]['notes']
for num in hrData:
if (cclass['category'] in hrData[num]['GP_Class'] and
hrData[num]['GP_Class'][cclass['category']] == cclass['class_id']):
for p in periods:
absData[p][h[0]][h[1]][num] = {
"name": hrData[num]['name'],
"eng_name": hrData[num]['eng_name'],
"alr_fill": ('signature' in tmpAbsData[currDate][p] and
cclass['class_id'] in tmpAbsData[currDate][p]['signature']),
"absent": False if not num in tmpAbsData[currDate][p] else tmpAbsData[currDate][p][num]
}
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('^')
homeroomData = db.child("Homerooms").child(homeroom[0]).child(
homeroom[1]).get(session['token']).val()
times = OrderedDict({
'm': '00:00',
'1': '08:15',
'2': '09:10',
'3': '10:05',
'4': '11:00',
'n': '11:55',
'5': '13:10',
'6': '14:05',
'7': '15:00',
'8': '15:53',
'9': '16:43',
'ph': '23:59'
})
currPeriod = ""
currTime = datetime.now(tz).strftime("%H:%M")
for i in times:
if (times[i] <= currTime and
currTime <= times[next_item(times, i)]):
currPeriod = i
break
absData = homeroomData["Absent"]
homeroomData.pop('Absent')
if 'placeholder' in homeroomData:
homeroomData.pop('placeholder')
currDate = ""
if fCommand == 'date':
currDate = fData
else:
for i in absData:
currDate = i
if i >= datetime.now(tz).strftime("%Y-%m-%d"):
break
return render_template('homeroom.html', absData=absData, homeroomCode=homeroom, homeroomData=homeroomData,
currDate=currDate, periods=['m', '1', '2', '3', '4', 'n', '5', '6', '7', '8', '9'], currPeriod=currPeriod)
else:
return redirect('/logout')
@ app.route('/', methods=['GET', 'POST']) @ app.route('/', methods=['GET', 'POST'])
def index(): def index():
if request.method == 'GET': if request.method == 'GET':
@ -267,356 +76,6 @@ def index():
return redirect('/manage') return redirect('/manage')
@ app.route('/manage', methods=['GET'])
def manage():
return manageProcess("", "")
@ app.route('/manage/date', methods=['POST'])
def manage_date():
return manageProcess("date", request.form['date'])
@app.route('/manage/admin', methods=['POST'])
def manage_admin():
data = [
request.form['grade'] + '^' + request.form['room'],
request.form['date']
]
return manageProcess("admin", data)
@ app.route('/manage/group_teach_publish', methods=['POST'])
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],
"homerooms": db.child("Classes").child(
"GP_Class").child(i).child("Homerooms").get(session['token']).val()
}
date = request.form['date']
period = request.form['period']
signature = request.form['signatureData']
formData = request.form.to_dict()
notes = ""
if 'notes' in request.form:
notes = request.form['notes']
formData.pop('notes')
signature = removeprefix(signature, 'data:image/png;base64,')
signature = bytes(signature, 'utf-8')
rand = str(date + '^' + cclass['category'] +
'^' + cclass['class_id'] + '^' + period)
rand += ".png"
with open(os.path.join('temp', rand), "wb") as fh:
fh.write(base64.decodebytes(signature))
storage.child(os.path.join('signatures', rand)
).put(os.path.join('temp', rand), session['token'])
formData.pop('signatureData')
formData.pop('date')
formData.pop('period')
for i in formData:
i = i.split('^')
db.child("Homerooms").child(i[1]).child(i[2]).child(
"Absent").child(date).child(period).update({i[3]: int(i[0])}, session['token'])
for h in cclass['homerooms']:
h = h.split('^')
db.child("Homerooms").child(h[0]).child(h[1]).child(
"Absent").child(date).child(period).child("signature").update({cclass['class_id']: str(storage.child(os.path.join('signatures', rand)).get_url(None))}, session['token'])
db.child("Homerooms").child(h[0]).child(h[1]).child(
"Absent").child(date).child(period).child("names").child(cclass['class_id']).set(cclass['name'], session['token'])
currPeriodData = db.child("Homerooms").child(h[0]).child(h[1]).child(
"Absent").child(date).child(period).get(session['token']).val()
if 'notes' in currPeriodData:
db.child("Homerooms").child(h[0]).child(h[1]).child(
"Absent").child(date).child(period).update({'notes': currPeriodData['notes']+'; '+notes}, session['token'])
else:
db.child("Homerooms").child(h[0]).child(h[1]).child(
"Absent").child(date).child(period).update({'notes': notes}, session['token'])
# upload notes
os.remove(os.path.join('temp', rand))
return redirect('/manage')
@ app.route('/manage/homeroom_abs', methods=['POST'])
def homeroom_abs_publish():
if (check_login_status()):
return redirect('/logout')
date = request.form['date']
homeroom = request.form['homeroom'].split('^')
period = request.form['period']
signature = request.form['signatureData']
formData = request.form.to_dict()
notes = ""
if 'notes' in request.form:
notes = request.form['notes']
formData.pop('notes')
signature = removeprefix(signature, 'data:image/png;base64,')
signature = bytes(signature, 'utf-8')
rand = str(date + '^' + homeroom[0] + '^' + homeroom[1] + '^' + period)
rand += ".png"
with open(os.path.join('temp', rand), "wb") as fh:
fh.write(base64.decodebytes(signature))
storage.child(os.path.join('signatures', rand)
).put(os.path.join('temp', rand), session['token'])
formData.pop('signatureData')
formData.pop('date')
formData.pop('homeroom')
formData.pop('period')
for i in formData:
i = i.split('^')
db.child("Homerooms").child(homeroom[0]).child(
homeroom[1]).child("Absent").child(date).child(period).update({i[1]: int(i[0])}, session['token'])
db.child("Homerooms").child(homeroom[0]).child(homeroom[1]).child(
"Absent").child(date).child(period).update({'signature': str(storage.child(os.path.join('signatures', rand)).get_url(None))}, session['token'])
db.child("Homerooms").child(homeroom[0]).child(homeroom[1]).child(
"Absent").child(date).child(period).update({'notes': notes}, session['token'])
os.remove(os.path.join('temp', rand))
return redirect('/manage')
@app.route('/manage/homeroom_confirm', methods=['POST'])
def homeroom_confirm():
if (check_login_status()):
return redirect('/logout')
date = request.form['date']
homeroom = request.form['homeroom'].split('^')
signature = request.form['signatureData']
signature = removeprefix(signature, 'data:image/png;base64,')
signature = bytes(signature, 'utf-8')
rand = str(date + '^' + homeroom[0] + '^' + homeroom[1] + '^' + 'hrCfrm')
rand += ".png"
with open(os.path.join('temp', rand), "wb") as fh:
fh.write(base64.decodebytes(signature))
storage.child(os.path.join('signatures', rand)
).put(os.path.join('temp', rand), session['token'])
db.child("Homerooms").child(homeroom[0]).child(homeroom[1]).child("Absent").child(date).update(
{"confirm": str(storage.child(os.path.join('signatures', rand)).get_url(None))}, session['token'])
os.remove(os.path.join('temp', rand))
return redirect('/manage')
@ app.route('/upload/1', methods=['GET', 'POST'])
def upload_homeroom():
if ((not check_login_status()) and check_permission()):
if request.method == 'GET':
return render_template('uploadcsv.html', title="Homeroom List", url="/upload/1")
elif request.method == 'POST':
try:
# get csv
gradec = request.form['gradeCode']
classc = request.form['classcode']
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:
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
})
else:
db.child("Homerooms").child(gradec).child(
classc).child(row['number']).set(row, session['token'])
# row['class'] row['number'] row['name'] row['eng_name']
os.remove(filepath)
except Exception as e:
os.remove(filepath)
return "Error. Please try again\n("+str(e)+")"
return "Successfully uploaded " + gradec + "-" + classc
else:
return redirect('/logout')
@ app.route('/upload/2', methods=['GET', 'POST'])
def upload_gp_classes():
if ((not check_login_status()) and check_permission()):
if request.method == 'GET':
return render_template('uploadcsv.html', title="Group Classes", url="/upload/2")
elif request.method == 'POST':
try:
csv_file = request.files['csv']
filepath = os.path.join('./temp', csv_file.filename)
csv_file.save(filepath)
csv_dict = pd.read_csv(filepath)
category_cnt = csv_dict.shape[1] - 1
for i in range(category_cnt):
tmp_csv = csv_dict[csv_dict.columns[i+1]].tolist()
for j in range(len(tmp_csv)):
if type(tmp_csv[j]) == float:
break
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": {
csv_dict.columns[i+1]: tmp_csv[j],
}
}, session['token'])
os.remove(filepath)
except Exception as e:
os.remove(filepath)
return "Error. Please try again\n("+str(e)+")"
return "Successfully uploaded"
else:
return redirect('/logout')
@ app.route('/upload/3', methods=['GET', 'POST'])
def upload_stud_in_group():
if ((not check_login_status()) and check_permission()):
if request.method == 'GET':
return render_template('uploadcsv.html', title="Student in Group List", url="/upload/3")
elif request.method == 'POST':
try:
gradec = request.form['gradeCode']
classc = request.form['classcode']
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)
headers = csv_dict.fieldnames
headers = headers[1:]
for h in headers:
db.child("Classes").child("GP_Class").child(
h).child("Homerooms").update({gradec+'^'+classc: 0}, session['token'])
for row in csv_dict:
for h in headers:
db.child("Homerooms").child(gradec).child(classc).child(
row['number']).child("GP_Class").update({h: row[h]}, session['token'])
os.remove(filepath)
except Exception as e:
os.remove(filepath)
return "Error. Please try again\n("+str(e)+")"
return "Successfully uploaded " + gradec + "-" + classc
else:
return redirect('/logout')
@ app.route('/upload/4', methods=['GET', 'POST'])
def upload_period_list():
if ((not check_login_status()) and check_permission()):
if request.method == 'GET':
return render_template('uploadcsv.html', title="Period List", url="/upload/4")
elif request.method == 'POST':
try:
# get csv
gradec = request.form['gradeCode']
classc = request.form['classcode']
csv_file = request.files['csv']
filepath = os.path.join('./temp', csv_file.filename)
csv_file.save(filepath)
csv_dict = pd.read_csv(filepath)
periodCodes = csv_dict['Period Day'].tolist()
for i in range(5):
tmp_csv = csv_dict[str(i+1)].tolist()
for j in range(len(tmp_csv)):
if not (periodCodes[j].endswith('-t')):
if type(tmp_csv[j]) == float:
db.child("Classes").child("Homeroom").child(gradec).child(classc).child(
str(i+1)).child(periodCodes[j]).update({'name': '--'}, session['token'])
else:
db.child("Classes").child("Homeroom").child(gradec).child(classc).child(
str(i+1)).child(periodCodes[j]).update({'name': tmp_csv[j]}, session['token'])
if not(periodCodes[j] == 'm' or periodCodes[j] == 'n'):
j += 1
db.child("Classes").child("Homeroom").child(gradec).child(classc).child(
str(i+1)).child(periodCodes[j-1]).update({'teacher': tmp_csv[j]}, session['token'])
os.remove(filepath)
except Exception as e:
os.remove(filepath)
return "Error. Please try again\n("+str(e)+")"
return "Successfully uploaded " + gradec + "-" + classc
else:
return redirect('/logout')
@ app.route('/upload/dates', methods=['GET', 'POST'])
def upload_dates():
if ((not check_login_status()) and check_permission()):
if request.method == 'GET':
return render_template('uploadcsv.html', title="School Days", url="/upload/dates")
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)
headers = csv_dict.fieldnames
temp = db.child("Homerooms").get(session['token']).val()
for row in csv_dict:
for h in headers:
for t in temp:
for i in temp[t]:
periodData = db.child("Classes").child(
"Homeroom").child(t).child(i).get(session['token']).val()
db.child("Homerooms").child(t).child(i).child(
"Absent").child(h).update({"dow": row[h]}, session['token'])
db.child("Homerooms").child(t).child(i).child(
"Absent").child(h).update(periodData[int(row[h])], session['token'])
os.remove(filepath)
except Exception as e:
os.remove(filepath)
return "Error. Please try again\n("+str(e)+")"
return "Successfully uploaded dates"
else:
return redirect('/logout')
@app.route('/upload/admin_acc', methods=['GET', 'POST'])
def upload_admin_acc():
if ((not check_login_status()) and check_permission()):
if request.method == 'GET':
return render_template('uploadcsv.html', title="Admin Accounts", url="/upload/admin_acc")
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:
auth.create_user_with_email_and_password(
row['username'] + '@group-attendance.fhjh.tp.edu.tw', row['password'])
user = auth.sign_in_with_email_and_password(
row['username'] + '@group-attendance.fhjh.tp.edu.tw', row['password'])
db.child("Users").child(user['localId']).update({
'permission': 'admin',
'username': row['username'],
'showUpload': row['permission']
}, session['token'])
os.remove(filepath)
except Exception as e:
os.remove(filepath)
return "Error. Please try again\n("+str(e)+")"
return "Successfully uploaded admin accounts"
else:
return redirect('/logout')
@ app.route('/logout', methods=['GET']) @ app.route('/logout', methods=['GET'])
def logout(): def logout():
session.clear() session.clear()

355
manage.py Normal file
View file

@ -0,0 +1,355 @@
from flask import *
from typing import OrderedDict
from flask import *
import pyrebase
from datetime import datetime
import pytz
import os
import base64
from dotenv import load_dotenv
load_dotenv()
manage = Blueprint('manage', __name__)
config = {
"apiKey": os.environ.get('apiKey'),
"authDomain": os.environ.get('authDomain'),
"databaseURL": os.environ.get('databaseURL'),
"storageBucket": os.environ.get('storageBucket'),
"serviceAccount": os.environ.get('serviceAccount'),
"messagingSenderId": os.environ.get('messagingSenderId'),
"appId": os.environ.get('appId'),
"measurementId": os.environ.get('measurementId'),
}
firebase = pyrebase.initialize_app(config)
db = firebase.database()
auth = firebase.auth()
storage = firebase.storage()
tz = pytz.timezone('Asia/Taipei')
def next_item(odic, key):
return list(odic)[list(odic.keys()).index(key) + 1]
def check_login_status():
return ('is_logged_in' not in session or
session['is_logged_in'] == False or
(datetime.now(tz) - session['loginTime']).total_seconds() > 3600)
def removeprefix(s, prefix):
if s.startswith(prefix):
return s[len(prefix):]
return s
def manageProcess(fCommand, fData):
if (check_login_status()):
return redirect('/logout')
# this is to fix a bug where pyrebase doesnt load the first request
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()
if pl == 'admin':
homerooms = db.child("Homerooms").get(session['token']).val()
currRoom = []
if fCommand == "admin":
currRoom = fData[0].split("^")
else:
for i in homerooms:
currRoom.append(i)
for j in homerooms[i]:
currRoom.append(j)
break
break
homeroomData = homerooms[currRoom[0]][currRoom[1]]
absData = homeroomData["Absent"]
homeroomData.pop('Absent')
if 'placeholder' in homeroomData:
homeroomData.pop('placeholder')
currDate = ""
if fCommand != "":
currDate = fData[1]
else:
for i in absData:
currDate = i
if i >= datetime.now(tz).strftime("%Y-%m-%d"):
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())
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()
cclass = {
"name": cateData['Class'][classes[i]]['name'],
"category": i,
"class_id": classes[i]
}
homerooms = cateData['Homerooms']
currDate = ""
confirmed = []
absData = {}
for h in homerooms:
h = h.split('^')
hrData = db.child("Homerooms").child(
h[0]).child(h[1]).get(session['token']).val()
tmpAbsData = hrData['Absent']
hrData.pop('Absent')
if 'placeholder' in hrData:
hrData.pop('placeholder')
periods = []
dow = ""
if currDate == "":
if fCommand == 'date':
currDate = fData
for j in tmpAbsData[currDate]:
if j == "dow":
dow = tmpAbsData[currDate][j]
continue
elif j == "confirm":
confirmed.append([h[0], h[1]])
continue
if (tmpAbsData[currDate][j]['name'] == 'GP' and
tmpAbsData[currDate][j]['teacher'] == cclass['category']):
periods.append(j)
else:
for i in tmpAbsData:
currDate = i
if i >= datetime.now(tz).strftime("%Y-%m-%d"):
tmp = False
for j in tmpAbsData[i]:
if j == "dow":
dow = tmpAbsData[i][j]
continue
elif j == "confirm":
confirmed.append([h[0], h[1]])
continue
if (tmpAbsData[i][j]['name'] == 'GP' and
tmpAbsData[i][j]['teacher'] == cclass['category']):
periods.append(j)
tmp = True
if tmp == True:
break
else:
for j in tmpAbsData[currDate]:
if j == "dow":
dow = tmpAbsData[currDate][j]
continue
elif j == "confirm":
confirmed.append([h[0], h[1]])
continue
if (tmpAbsData[currDate][j]['name'] == 'GP' and
tmpAbsData[currDate][j]['teacher'] == cclass['category']):
periods.append(j)
for p in periods:
if not p in absData:
absData[p] = {}
for p in periods:
if not h[0] in absData[p]:
absData[p][h[0]] = {}
absData[p][h[0]][h[1]] = {}
if 'notes' in tmpAbsData[currDate][p]:
absData[p][h[0]][h[1]
]['notes'] = tmpAbsData[currDate][p]['notes']
for num in hrData:
if (cclass['category'] in hrData[num]['GP_Class'] and
hrData[num]['GP_Class'][cclass['category']] == cclass['class_id']):
for p in periods:
absData[p][h[0]][h[1]][num] = {
"name": hrData[num]['name'],
"eng_name": hrData[num]['eng_name'],
"alr_fill": ('signature' in tmpAbsData[currDate][p] and
cclass['class_id'] in tmpAbsData[currDate][p]['signature']),
"absent": False if not num in tmpAbsData[currDate][p] else tmpAbsData[currDate][p][num]
}
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('^')
homeroomData = db.child("Homerooms").child(homeroom[0]).child(
homeroom[1]).get(session['token']).val()
times = OrderedDict({
'm': '00:00',
'1': '08:15',
'2': '09:10',
'3': '10:05',
'4': '11:00',
'n': '11:55',
'5': '13:10',
'6': '14:05',
'7': '15:00',
'8': '15:53',
'9': '16:43',
'ph': '23:59'
})
currPeriod = ""
currTime = datetime.now(tz).strftime("%H:%M")
for i in times:
if (times[i] <= currTime and
currTime <= times[next_item(times, i)]):
currPeriod = i
break
absData = homeroomData["Absent"]
homeroomData.pop('Absent')
if 'placeholder' in homeroomData:
homeroomData.pop('placeholder')
currDate = ""
if fCommand == 'date':
currDate = fData
else:
for i in absData:
currDate = i
if i >= datetime.now(tz).strftime("%Y-%m-%d"):
break
return render_template('homeroom.html', absData=absData, homeroomCode=homeroom, homeroomData=homeroomData,
currDate=currDate, periods=['m', '1', '2', '3', '4', 'n', '5', '6', '7', '8', '9'], currPeriod=currPeriod)
else:
return redirect('/logout')
@manage.route('/manage', methods=['GET'])
def manageRoot():
return manageProcess("", "")
@manage.route('/manage/date', methods=['POST'])
def manage_date():
return manageProcess("date", request.form['date'])
@manage.route('/manage/admin', methods=['POST'])
def manage_admin():
data = [
request.form['grade'] + '^' + request.form['room'],
request.form['date']
]
return manageProcess("admin", data)
@manage.route('/manage/group_teach_publish', methods=['POST'])
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],
"homerooms": db.child("Classes").child(
"GP_Class").child(i).child("Homerooms").get(session['token']).val()
}
date = request.form['date']
period = request.form['period']
signature = request.form['signatureData']
formData = request.form.to_dict()
notes = ""
if 'notes' in request.form:
notes = request.form['notes']
formData.pop('notes')
signature = removeprefix(signature, 'data:image/png;base64,')
signature = bytes(signature, 'utf-8')
rand = str(date + '^' + cclass['category'] +
'^' + cclass['class_id'] + '^' + period)
rand += ".png"
with open(os.path.join('temp', rand), "wb") as fh:
fh.write(base64.decodebytes(signature))
storage.child(os.path.join('signatures', rand)
).put(os.path.join('temp', rand), session['token'])
formData.pop('signatureData')
formData.pop('date')
formData.pop('period')
for i in formData:
i = i.split('^')
db.child("Homerooms").child(i[1]).child(i[2]).child(
"Absent").child(date).child(period).update({i[3]: int(i[0])}, session['token'])
for h in cclass['homerooms']:
h = h.split('^')
db.child("Homerooms").child(h[0]).child(h[1]).child(
"Absent").child(date).child(period).child("signature").update({cclass['class_id']: str(storage.child(os.path.join('signatures', rand)).get_url(None))}, session['token'])
db.child("Homerooms").child(h[0]).child(h[1]).child(
"Absent").child(date).child(period).child("names").child(cclass['class_id']).set(cclass['name'], session['token'])
currPeriodData = db.child("Homerooms").child(h[0]).child(h[1]).child(
"Absent").child(date).child(period).get(session['token']).val()
if 'notes' in currPeriodData:
db.child("Homerooms").child(h[0]).child(h[1]).child(
"Absent").child(date).child(period).update({'notes': currPeriodData['notes']+'; '+notes}, session['token'])
else:
db.child("Homerooms").child(h[0]).child(h[1]).child(
"Absent").child(date).child(period).update({'notes': notes}, session['token'])
# upload notes
os.remove(os.path.join('temp', rand))
return redirect('/manage')
@manage.route('/manage/homeroom_abs', methods=['POST'])
def homeroom_abs_publish():
if (check_login_status()):
return redirect('/logout')
date = request.form['date']
homeroom = request.form['homeroom'].split('^')
period = request.form['period']
signature = request.form['signatureData']
formData = request.form.to_dict()
notes = ""
if 'notes' in request.form:
notes = request.form['notes']
formData.pop('notes')
signature = removeprefix(signature, 'data:image/png;base64,')
signature = bytes(signature, 'utf-8')
rand = str(date + '^' + homeroom[0] + '^' + homeroom[1] + '^' + period)
rand += ".png"
with open(os.path.join('temp', rand), "wb") as fh:
fh.write(base64.decodebytes(signature))
storage.child(os.path.join('signatures', rand)
).put(os.path.join('temp', rand), session['token'])
formData.pop('signatureData')
formData.pop('date')
formData.pop('homeroom')
formData.pop('period')
for i in formData:
i = i.split('^')
db.child("Homerooms").child(homeroom[0]).child(
homeroom[1]).child("Absent").child(date).child(period).update({i[1]: int(i[0])}, session['token'])
db.child("Homerooms").child(homeroom[0]).child(homeroom[1]).child(
"Absent").child(date).child(period).update({'signature': str(storage.child(os.path.join('signatures', rand)).get_url(None))}, session['token'])
db.child("Homerooms").child(homeroom[0]).child(homeroom[1]).child(
"Absent").child(date).child(period).update({'notes': notes}, session['token'])
os.remove(os.path.join('temp', rand))
return redirect('/manage')
@manage.route('/manage/homeroom_confirm', methods=['POST'])
def homeroom_confirm():
if (check_login_status()):
return redirect('/logout')
date = request.form['date']
homeroom = request.form['homeroom'].split('^')
signature = request.form['signatureData']
signature = removeprefix(signature, 'data:image/png;base64,')
signature = bytes(signature, 'utf-8')
rand = str(date + '^' + homeroom[0] + '^' + homeroom[1] + '^' + 'hrCfrm')
rand += ".png"
with open(os.path.join('temp', rand), "wb") as fh:
fh.write(base64.decodebytes(signature))
storage.child(os.path.join('signatures', rand)
).put(os.path.join('temp', rand), session['token'])
db.child("Homerooms").child(homeroom[0]).child(homeroom[1]).child("Absent").child(date).update(
{"confirm": str(storage.child(os.path.join('signatures', rand)).get_url(None))}, session['token'])
os.remove(os.path.join('temp', rand))
return redirect('/manage')

View file

@ -23,11 +23,16 @@
</head> </head>
<body> <body>
<div class="showTime">Current Time: <span id="showTime"></span></div> <div class="showTime"><span id="showTime"></span></div>
<div class="container"> <div class="container">
<h1 class="margin-top">Admin View | 管理頁面</h1> <h1 class="margin-top">Admin View | 管理頁面</h1>
<h2 class="margin-top">{{homeroomCode[0]}} {{homeroomCode[1]}}</h2> <h2 class="margin-top">{{homeroomCode[0]}} {{homeroomCode[1]}}</h2>
<h2>[{{currDate}}]</h2> <h2>[{{currDate}}]</h2>
{% if 'confirm' in absData[currDate] %}
<h2 style="color: rgb(61, 194, 0); text-align: center;">Homeroom Confirmed 班導已確認</h2>
{% else %}
<h2 style="color: red; text-align: center;">Homeroom NOT Confirmed 班導尚未確認</h2>
{% endif %}
<a href="/logout"><button class="btn btn-primary logout margin-top">Logout 登出</button></a> <a href="/logout"><button class="btn btn-primary logout margin-top">Logout 登出</button></a>
<div class="container margin-bottom"> <div class="container margin-bottom">
<form action="/manage/admin" id="adminSelForm" method="post"> <form action="/manage/admin" id="adminSelForm" method="post">
@ -135,18 +140,13 @@
</div> </div>
{% endfor %} {% endfor %}
{% endif %} {% endif %}
{% if 'confirm' in absData[currDate] %}
<p style="color: blue; text-align: center;">Homeroom Teacher Confirmed 班導已確認</p>
{% else %}
<p style="color: red; text-align: center;">Homeroom Teacher NOT Confirmed 班導尚未確認</p>
{% endif %}
{% for c in range(periods|length + 1) %} {% for c in range(periods|length + 1) %}
{% if c % 4 == 0 %} {% if c % 4 == 0 %}
<div class="row signatures"> <div class="row signatures">
{% endif %} {% endif %}
<div class="col half"> <div class="col half">
{% if c == 0 %} {% if c == 0 %}
<div class="row">Homeroom Teacher</div> <div class="row">Homeroom Teacher 導師</div>
{% if 'confirm' in absData[currDate] %} {% if 'confirm' in absData[currDate] %}
<div class="row"><img src="{{absData[currDate]['confirm']}}" alt=""></div> <div class="row"><img src="{{absData[currDate]['confirm']}}" alt=""></div>
{% else %} {% else %}

View file

@ -23,7 +23,7 @@
</head> </head>
<body> <body>
<div class="showTime">Current Time: <span id="showTime"></span></div> <div class="showTime"><span id="showTime"></span></div>
<div class="container"> <div class="container">
<h1 class="margin-top">Group Class View | 分組課頁面</h1> <h1 class="margin-top">Group Class View | 分組課頁面</h1>
<h2 class="margin-top">{{cclass['category']}}: {{cclass['class_id']}}: {{cclass['name']}}</h2> <h2 class="margin-top">{{cclass['category']}}: {{cclass['class_id']}}: {{cclass['name']}}</h2>
@ -188,8 +188,8 @@
document.getElementById('late^' + string).checked = false; document.getElementById('late^' + string).checked = false;
} }
</script> </script>
<div id="loading" style="text-align:center; width:100%; max-height:100%; display:none;"><img <div id="loading" style="text-align:center; width:100%; display:none;"><img src="/static/loading.gif" alt=""
src="/static/loading.gif" alt="" style="width:100%;" /> style="height:100%;" />
</div> </div>
{% include 'footer.html' %} {% include 'footer.html' %}
<script> <script>

View file

@ -24,7 +24,7 @@
</head> </head>
<body> <body>
<div class="showTime">Current Time: <span id="showTime"></span></div> <div class="showTime"><span id="showTime"></span></div>
<div class="container"> <div class="container">
<h1 class="margin-top">Homeroom View | 班級主頁</h1> <h1 class="margin-top">Homeroom View | 班級主頁</h1>
<h2 class="margin-top">{{homeroomCode[0]}}{{homeroomCode[1]}}</h2> <h2 class="margin-top">{{homeroomCode[0]}}{{homeroomCode[1]}}</h2>

View file

@ -23,7 +23,7 @@
</head> </head>
<body> <body>
<div class="showTime">Current Time: <span id="showTime"></span></div> <div class="showTime"><span id="showTime"></span></div>
<div class="container"> <div class="container">
<h1 class="margin-top margin-bottom">Attendance 點名系統 (β) | Login 登入</h1> <h1 class="margin-top margin-bottom">Attendance 點名系統 (β) | Login 登入</h1>
<div class="row"> <div class="row">

View file

@ -22,7 +22,7 @@
</head> </head>
<body> <body>
<div class="showTime">Current Time: <span id="showTime"></span></div> <div class="showTime"><span id="showTime"></span></div>
<div class="container"> <div class="container">
<div class="row"> <div class="row">
<div class="col"></div> <div class="col"></div>

249
upload.py Normal file
View file

@ -0,0 +1,249 @@
from flask import *
import pyrebase
from datetime import datetime
import pytz
import csv
import os
import pandas as pd
from dotenv import load_dotenv
load_dotenv()
upload = Blueprint('upload', __name__)
config = {
"apiKey": os.environ.get('apiKey'),
"authDomain": os.environ.get('authDomain'),
"databaseURL": os.environ.get('databaseURL'),
"storageBucket": os.environ.get('storageBucket'),
"serviceAccount": os.environ.get('serviceAccount'),
"messagingSenderId": os.environ.get('messagingSenderId'),
"appId": os.environ.get('appId'),
"measurementId": os.environ.get('measurementId'),
}
firebase = pyrebase.initialize_app(config)
db = firebase.database()
auth = firebase.auth()
tz = pytz.timezone('Asia/Taipei')
def check_login_status():
return ('is_logged_in' not in session or
session['is_logged_in'] == False or
(datetime.now(tz) - session['loginTime']).total_seconds() > 3600)
def check_permission():
return (db.child('Users').child(session['uid']).child('permission').get(session['token']).val() == 'admin' and
db.child("Users").child(session['uid']).child("showUpload").get(session['token']).val() == '1')
@upload.route('/upload/1', methods=['GET', 'POST'])
def upload_homeroom():
if ((not check_login_status()) and check_permission()):
if request.method == 'GET':
return render_template('uploadcsv.html', title="Homeroom List", url="/upload/1")
elif request.method == 'POST':
try:
# get csv
gradec = request.form['gradeCode']
classc = request.form['classcode']
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:
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
})
else:
db.child("Homerooms").child(gradec).child(
classc).child(row['number']).set(row, session['token'])
# row['class'] row['number'] row['name'] row['eng_name']
os.remove(filepath)
except Exception as e:
os.remove(filepath)
return "Error. Please try again\n("+str(e)+")"
return "Successfully uploaded " + gradec + "-" + classc
else:
return redirect('/logout')
@upload.route('/upload/2', methods=['GET', 'POST'])
def upload_gp_classes():
if ((not check_login_status()) and check_permission()):
if request.method == 'GET':
return render_template('uploadcsv.html', title="Group Classes", url="/upload/2")
elif request.method == 'POST':
try:
csv_file = request.files['csv']
filepath = os.path.join('./temp', csv_file.filename)
csv_file.save(filepath)
csv_dict = pd.read_csv(filepath)
category_cnt = csv_dict.shape[1] - 1
for i in range(category_cnt):
tmp_csv = csv_dict[csv_dict.columns[i+1]].tolist()
for j in range(len(tmp_csv)):
if type(tmp_csv[j]) == float:
break
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": {
csv_dict.columns[i+1]: tmp_csv[j],
}
}, session['token'])
os.remove(filepath)
except Exception as e:
os.remove(filepath)
return "Error. Please try again\n("+str(e)+")"
return "Successfully uploaded"
else:
return redirect('/logout')
@upload.route('/upload/3', methods=['GET', 'POST'])
def upload_stud_in_group():
if ((not check_login_status()) and check_permission()):
if request.method == 'GET':
return render_template('uploadcsv.html', title="Student in Group List", url="/upload/3")
elif request.method == 'POST':
try:
gradec = request.form['gradeCode']
classc = request.form['classcode']
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)
headers = csv_dict.fieldnames
headers = headers[1:]
for h in headers:
db.child("Classes").child("GP_Class").child(
h).child("Homerooms").update({gradec+'^'+classc: 0}, session['token'])
for row in csv_dict:
for h in headers:
db.child("Homerooms").child(gradec).child(classc).child(
row['number']).child("GP_Class").update({h: row[h]}, session['token'])
os.remove(filepath)
except Exception as e:
os.remove(filepath)
return "Error. Please try again\n("+str(e)+")"
return "Successfully uploaded " + gradec + "-" + classc
else:
return redirect('/logout')
@upload.route('/upload/4', methods=['GET', 'POST'])
def upload_period_list():
if ((not check_login_status()) and check_permission()):
if request.method == 'GET':
return render_template('uploadcsv.html', title="Period List", url="/upload/4")
elif request.method == 'POST':
try:
# get csv
gradec = request.form['gradeCode']
classc = request.form['classcode']
csv_file = request.files['csv']
filepath = os.path.join('./temp', csv_file.filename)
csv_file.save(filepath)
csv_dict = pd.read_csv(filepath)
periodCodes = csv_dict['Period Day'].tolist()
for i in range(5):
tmp_csv = csv_dict[str(i+1)].tolist()
for j in range(len(tmp_csv)):
if not (periodCodes[j].endswith('-t')):
if type(tmp_csv[j]) == float:
db.child("Classes").child("Homeroom").child(gradec).child(classc).child(
str(i+1)).child(periodCodes[j]).update({'name': '--'}, session['token'])
else:
db.child("Classes").child("Homeroom").child(gradec).child(classc).child(
str(i+1)).child(periodCodes[j]).update({'name': tmp_csv[j]}, session['token'])
if not(periodCodes[j] == 'm' or periodCodes[j] == 'n'):
j += 1
db.child("Classes").child("Homeroom").child(gradec).child(classc).child(
str(i+1)).child(periodCodes[j-1]).update({'teacher': tmp_csv[j]}, session['token'])
os.remove(filepath)
except Exception as e:
os.remove(filepath)
return "Error. Please try again\n("+str(e)+")"
return "Successfully uploaded " + gradec + "-" + classc
else:
return redirect('/logout')
@upload.route('/upload/dates', methods=['GET', 'POST'])
def upload_dates():
if ((not check_login_status()) and check_permission()):
if request.method == 'GET':
return render_template('uploadcsv.html', title="School Days", url="/upload/dates")
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)
headers = csv_dict.fieldnames
temp = db.child("Homerooms").get(session['token']).val()
for row in csv_dict:
for h in headers:
for t in temp:
for i in temp[t]:
periodData = db.child("Classes").child(
"Homeroom").child(t).child(i).get(session['token']).val()
db.child("Homerooms").child(t).child(i).child(
"Absent").child(h).update({"dow": row[h]}, session['token'])
db.child("Homerooms").child(t).child(i).child(
"Absent").child(h).update(periodData[int(row[h])], session['token'])
os.remove(filepath)
except Exception as e:
os.remove(filepath)
return "Error. Please try again\n("+str(e)+")"
return "Successfully uploaded dates"
else:
return redirect('/logout')
@upload.route('/upload/admin_acc', methods=['GET', 'POST'])
def upload_admin_acc():
if ((not check_login_status()) and check_permission()):
if request.method == 'GET':
return render_template('uploadcsv.html', title="Admin Accounts", url="/upload/admin_acc")
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:
auth.create_user_with_email_and_password(
row['username'] + '@group-attendance.fhjh.tp.edu.tw', row['password'])
user = auth.sign_in_with_email_and_password(
row['username'] + '@group-attendance.fhjh.tp.edu.tw', row['password'])
db.child("Users").child(user['localId']).update({
'permission': 'admin',
'username': row['username'],
'showUpload': row['permission']
}, session['token'])
os.remove(filepath)
except Exception as e:
os.remove(filepath)
return "Error. Please try again\n("+str(e)+")"
return "Successfully uploaded admin accounts"
else:
return redirect('/logout')