first commit

This commit is contained in:
Aaron Lee 2021-09-09 21:29:31 +08:00
commit 47d685568e
15 changed files with 562 additions and 0 deletions

35
911_namelist.csv Normal file
View file

@ -0,0 +1,35 @@
number,name,eng_name
1,朱昱翧,Themis
2,余欣璇,Zoe
3,吳丞育,Audrey
4,吳欣芃,Lisa
5,吳苡瑄,Rachel
6,王怡捷,Audrey
7,林子琳,Emma
8,林思佑,Una
9,林珈年,Jessica
10,姜心唯,Misha
11,張庭暄,Chang
12,許詠淳,Catherine
13,陳宣彤,idk
14,羅子珊,Shannon
15,蘇宜柔,Chloe
16,王邦熹,Wallace
17,李秉謙,Alan
18,劉青懷,idk
19,林稟翔,Wilbert
20,柯喬勳,Joshua
21,馮顗中,idk
22,張睿恩,Brian
23,姜廉竣,idk
24,陳允昊,Jeremy
25,陳宣豪,Demetris
26,陳宥嘉,Joseph
27,陳麟泳,Aaron
28,賀凱強,Jonathan
29,楊上霆,Chase
30,楊承武,Ben
31,廖建瑋,Daniel
32,潘逸,James
33,朱禹安,Iforgot
34,徐敏萱,idk
1 number name eng_name
2 1 朱昱翧 Themis
3 2 余欣璇 Zoe
4 3 吳丞育 Audrey
5 4 吳欣芃 Lisa
6 5 吳苡瑄 Rachel
7 6 王怡捷 Audrey
8 7 林子琳 Emma
9 8 林思佑 Una
10 9 林珈年 Jessica
11 10 姜心唯 Misha
12 11 張庭暄 Chang
13 12 許詠淳 Catherine
14 13 陳宣彤 idk
15 14 羅子珊 Shannon
16 15 蘇宜柔 Chloe
17 16 王邦熹 Wallace
18 17 李秉謙 Alan
19 18 劉青懷 idk
20 19 林稟翔 Wilbert
21 20 柯喬勳 Joshua
22 21 馮顗中 idk
23 22 張睿恩 Brian
24 23 姜廉竣 idk
25 24 陳允昊 Jeremy
26 25 陳宣豪 Demetris
27 26 陳宥嘉 Joseph
28 27 陳麟泳 Aaron
29 28 賀凱強 Jonathan
30 29 楊上霆 Chase
31 30 楊承武 Ben
32 31 廖建瑋 Daniel
33 32 潘逸 James
34 33 朱禹安 Iforgot
35 34 徐敏萱 idk

35
911_simple_gplist.csv Normal file
View file

@ -0,0 +1,35 @@
number,3-IG
1,1103-01
2,1103-01
3,1103-02
4,1103-01
5,1103-01
6,1103-02
7,1103-01
8,1103-01
9,1103-01
10,1103-01
11,1103-01
12,1103-01
13,1103-02
14,1103-01
15,1103-02
16,1103-01
17,1103-02
18,1103-02
19,1103-01
20,1103-02
21,1103-01
22,1103-02
23,1103-01
24,1103-02
25,1103-02
26,1103-02
27,1103-01
28,1103-02
29,1103-01
30,1103-01
31,1103-01
32,1103-01
33,1103-02
34,1103-01
1 number 3-IG
2 1 1103-01
3 2 1103-01
4 3 1103-02
5 4 1103-01
6 5 1103-01
7 6 1103-02
8 7 1103-01
9 8 1103-01
10 9 1103-01
11 10 1103-01
12 11 1103-01
13 12 1103-01
14 13 1103-02
15 14 1103-01
16 15 1103-02
17 16 1103-01
18 17 1103-02
19 18 1103-02
20 19 1103-01
21 20 1103-02
22 21 1103-01
23 22 1103-02
24 23 1103-01
25 24 1103-02
26 25 1103-02
27 26 1103-02
28 27 1103-01
29 28 1103-02
30 29 1103-01
31 30 1103-01
32 31 1103-01
33 32 1103-01
34 33 1103-02
35 34 1103-01

35
912_beforeformat.csv Normal file
View file

@ -0,0 +1,35 @@
number,name,eng_name,3-IG
1,王子芯,Heidi,1103-01
2,朱宸儀,Megan,1103-01
3,牟奇薇,Summer,1103-02
4,吳偲梵,Sophia,1103-01
5,林書誼,Charlotte,1103-01
6,林葦亭,Chelsea,1103-02
7,凌孟妍,Iris,1103-01
8,翁翊婷,Evelyn,1103-01
9,郭倚熏,Patty,1103-01
10,陳宣穎,Renee,1103-01
11,曾若霏,Danielle,1103-01
12,湯家綺,Joanna,1103-01
13,黃以甯,Kate,1103-02
14,黃玄,Cheryl,1103-01
15,劉煒琪,Winona,1103-02
16,潘俞希,Alina,1103-01
17,鄭軒,Jasper,1103-02
18,吳彥縢,Austin,1103-02
19,吳昶佑,Eric,1103-01
20,李翊愷,Aaron Lee,1103-02
21,李翊誠,Alex,1103-01
22,曹庭睿,Alvin,1103-02
23,莊家睿,Gary,1103-01
24,張馨予,Cindy,1103-02
25,常有慈,Cindy,1103-02
26,陳柏元,Michael,1103-02
27,陳雋喆,Derek,1103-01
28,曾柏皓,Cory,1103-02
29,黃獻主,Arthur,1103-01
30,盧秉漢,Hiro,1103-01
31,李文,Tom,1103-01
32,謝承霖,Walter,1103-01
33,關義,Aaron Kuan,1103-02
34,謝佾儒,Yi-Ju,1103-01
1 number name eng_name 3-IG
2 1 王子芯 Heidi 1103-01
3 2 朱宸儀 Megan 1103-01
4 3 牟奇薇 Summer 1103-02
5 4 吳偲梵 Sophia 1103-01
6 5 林書誼 Charlotte 1103-01
7 6 林葦亭 Chelsea 1103-02
8 7 凌孟妍 Iris 1103-01
9 8 翁翊婷 Evelyn 1103-01
10 9 郭倚熏 Patty 1103-01
11 10 陳宣穎 Renee 1103-01
12 11 曾若霏 Danielle 1103-01
13 12 湯家綺 Joanna 1103-01
14 13 黃以甯 Kate 1103-02
15 14 黃玄 Cheryl 1103-01
16 15 劉煒琪 Winona 1103-02
17 16 潘俞希 Alina 1103-01
18 17 鄭軒 Jasper 1103-02
19 18 吳彥縢 Austin 1103-02
20 19 吳昶佑 Eric 1103-01
21 20 李翊愷 Aaron Lee 1103-02
22 21 李翊誠 Alex 1103-01
23 22 曹庭睿 Alvin 1103-02
24 23 莊家睿 Gary 1103-01
25 24 張馨予 Cindy 1103-02
26 25 常有慈 Cindy 1103-02
27 26 陳柏元 Michael 1103-02
28 27 陳雋喆 Derek 1103-01
29 28 曾柏皓 Cory 1103-02
30 29 黃獻主 Arthur 1103-01
31 30 盧秉漢 Hiro 1103-01
32 31 李文 Tom 1103-01
33 32 謝承霖 Walter 1103-01
34 33 關義 Aaron Kuan 1103-02
35 34 謝佾儒 Yi-Ju 1103-01

35
912_gplist.csv Normal file
View file

@ -0,0 +1,35 @@
number,3-IG,2-TEST
1,1103-01,1102-5
2,1103-01,1102-5
3,1103-02,1102-5
4,1103-01,1102-5
5,1103-01,1102-5
6,1103-02,1102-5
7,1103-01,1102-5
8,1103-01,1102-5
9,1103-01,1102-5
10,1103-01,1102-5
11,1103-01,1102-5
12,1103-01,1102-5
13,1103-02,1102-5
14,1103-01,1102-5
15,1103-02,1102-5
16,1103-01,1102-5
17,1103-02,1102-5
18,1103-02,1102-5
19,1103-01,1102-5
20,1103-02,1102-5
21,1103-01,1102-9
22,1103-02,1102-9
23,1103-01,1102-9
24,1103-02,1102-9
25,1103-02,1102-9
26,1103-02,1102-9
27,1103-01,1102-9
28,1103-02,1102-9
29,1103-01,1102-9
30,1103-01,1102-9
31,1103-01,1102-9
32,1103-01,1102-9
33,1103-02,1102-9
34,1103-01,1102-9
1 number 3-IG 2-TEST
2 1 1103-01 1102-5
3 2 1103-01 1102-5
4 3 1103-02 1102-5
5 4 1103-01 1102-5
6 5 1103-01 1102-5
7 6 1103-02 1102-5
8 7 1103-01 1102-5
9 8 1103-01 1102-5
10 9 1103-01 1102-5
11 10 1103-01 1102-5
12 11 1103-01 1102-5
13 12 1103-01 1102-5
14 13 1103-02 1102-5
15 14 1103-01 1102-5
16 15 1103-02 1102-5
17 16 1103-01 1102-5
18 17 1103-02 1102-5
19 18 1103-02 1102-5
20 19 1103-01 1102-5
21 20 1103-02 1102-5
22 21 1103-01 1102-9
23 22 1103-02 1102-9
24 23 1103-01 1102-9
25 24 1103-02 1102-9
26 25 1103-02 1102-9
27 26 1103-02 1102-9
28 27 1103-01 1102-9
29 28 1103-02 1102-9
30 29 1103-01 1102-9
31 30 1103-01 1102-9
32 31 1103-01 1102-9
33 32 1103-01 1102-9
34 33 1103-02 1102-9
35 34 1103-01 1102-9

35
912_namelist.csv Normal file
View file

@ -0,0 +1,35 @@
number,name,eng_name
1,王子芯,Heidi
2,朱宸儀,Megan
3,牟奇薇,Summer
4,吳偲梵,Sophia
5,林書誼,Charlotte
6,林葦亭,Chelsea
7,凌孟妍,Iris
8,翁翊婷,Evelyn
9,郭倚熏,Patty
10,陳宣穎,Renee
11,曾若霏,Danielle
12,湯家綺,Joanna
13,黃以甯,Kate
14,黃玄,Cheryl
15,劉煒琪,Winona
16,潘俞希,Alina
17,鄭軒,Jasper
18,吳彥縢,Austin
19,吳昶佑,Eric
20,李翊愷,Aaron Lee
21,李翊誠,Alex
22,曹庭睿,Alvin
23,莊家睿,Gary
24,張馨予,Cindy
25,常有慈,Cindy
26,陳柏元,Michael
27,陳雋喆,Derek
28,曾柏皓,Cory
29,黃獻主,Arthur
30,盧秉漢,Hiro
31,李文,Tom
32,謝承霖,Walter
33,關義,Aaron Kuan
34,謝佾儒,Yi-Ju
1 number name eng_name
2 1 王子芯 Heidi
3 2 朱宸儀 Megan
4 3 牟奇薇 Summer
5 4 吳偲梵 Sophia
6 5 林書誼 Charlotte
7 6 林葦亭 Chelsea
8 7 凌孟妍 Iris
9 8 翁翊婷 Evelyn
10 9 郭倚熏 Patty
11 10 陳宣穎 Renee
12 11 曾若霏 Danielle
13 12 湯家綺 Joanna
14 13 黃以甯 Kate
15 14 黃玄 Cheryl
16 15 劉煒琪 Winona
17 16 潘俞希 Alina
18 17 鄭軒 Jasper
19 18 吳彥縢 Austin
20 19 吳昶佑 Eric
21 20 李翊愷 Aaron Lee
22 21 李翊誠 Alex
23 22 曹庭睿 Alvin
24 23 莊家睿 Gary
25 24 張馨予 Cindy
26 25 常有慈 Cindy
27 26 陳柏元 Michael
28 27 陳雋喆 Derek
29 28 曾柏皓 Cory
30 29 黃獻主 Arthur
31 30 盧秉漢 Hiro
32 31 李文 Tom
33 32 謝承霖 Walter
34 33 關義 Aaron Kuan
35 34 謝佾儒 Yi-Ju

35
912_simple_gplist.csv Normal file
View file

@ -0,0 +1,35 @@
number,3-IG
1,1103-01
2,1103-01
3,1103-02
4,1103-01
5,1103-01
6,1103-02
7,1103-01
8,1103-01
9,1103-01
10,1103-01
11,1103-01
12,1103-01
13,1103-02
14,1103-01
15,1103-02
16,1103-01
17,1103-02
18,1103-02
19,1103-01
20,1103-02
21,1103-01
22,1103-02
23,1103-01
24,1103-02
25,1103-02
26,1103-02
27,1103-01
28,1103-02
29,1103-01
30,1103-01
31,1103-01
32,1103-01
33,1103-02
34,1103-01
1 number 3-IG
2 1 1103-01
3 2 1103-01
4 3 1103-02
5 4 1103-01
6 5 1103-01
7 6 1103-02
8 7 1103-01
9 8 1103-01
10 9 1103-01
11 10 1103-01
12 11 1103-01
13 12 1103-01
14 13 1103-02
15 14 1103-01
16 15 1103-02
17 16 1103-01
18 17 1103-02
19 18 1103-02
20 19 1103-01
21 20 1103-02
22 21 1103-01
23 22 1103-02
24 23 1103-01
25 24 1103-02
26 25 1103-02
27 26 1103-02
28 27 1103-01
29 28 1103-02
30 29 1103-01
31 30 1103-01
32 31 1103-01
33 32 1103-01
34 33 1103-02
35 34 1103-01

206
app.py Normal file
View file

@ -0,0 +1,206 @@
from flask import *
import pyrebase
from datetime import datetime
import pytz
from sendgrid import SendGridAPIClient
from sendgrid.helpers.mail import Mail
import csv
import os
from dotenv import load_dotenv
from pprint import pprint
load_dotenv()
app = Flask(__name__)
app.config['SECRET_KEY'] = os.environ.get('SECRET_KEY')
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)
@ app.route('/', methods=['GET', 'POST'])
def index():
if request.method == 'GET':
if check_login_status():
return render_template('login.html', error=False)
return redirect('/manage')
elif request.method == 'POST':
if check_login_status():
try:
user = auth.sign_in_with_email_and_password(
request.form['username'] + "@group-attendence.fhjh.tp.edu.tw", request.form['password'])
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('/manage')
except Exception as e:
return render_template('login.html', error=True)
else:
return redirect('/manage')
@app.route('/manage', methods=['GET'])
def manage():
pl = db.child("Users").child(
session['uid']).child("permission").get().val()
print(pl)
s = str(pl)
if pl == 'admin':
return s
elif pl == 'group':
classes = db.child("Users").child(
session['uid']).child("class").get().val()
cclass = {}
for i in classes:
cclass = {
"name": db.child("Classes").child(i).child(
"Class").child(classes[i]).child("name").get().val(),
"category": i,
"class_id": classes[i]
}
print("got class")
students = db.child("Classes").child(cclass['category']).child(
"Class").child(cclass['class_id']).child("Students").get().val()
all_stud_list = {}
for homeroom in students:
print(homeroom)
all_stud_list[homeroom] = {}
if type(students[homeroom]) == list:
i = 0
for student in students[homeroom]:
if student == 0:
# print(i)
# print(db.child("Homerooms").child(
# homeroom).child(i).child("name").get().val())
all_stud_list[homeroom][i] = {
"name": db.child("Homerooms").child(homeroom).child(i).child("name").get().val(),
"eng_name": db.child("Homerooms").child(homeroom).child(i).child("eng_name").get().val(),
}
i += 1
else:
for student in students[homeroom]:
all_stud_list[homeroom][student] = {
"name": db.child("Homerooms").child(homeroom).child(student).child("name").get().val(),
"eng_name": db.child("Homerooms").child(homeroom).child(student).child("eng_name").get().val(),
}
print("got students")
# for homeroom in all_stud_list:
# for student in all_stud_list[homeroom]:
# print("homeroom: ", homeroom)
# print("student: ", student)
# print("all_stud_list['homeroom']['student']['name']: ",
# all_stud_list['homeroom']['student']['name'])
# print("all_stud_list['homeroom']['student']['eng_name']: ",
# all_stud_list['homeroom']['student']['eng_name'])
# get dates
dates = db.child("Classes").child(
cclass['category']).child("Dates").get().val()
for i in dates:
dates[i].pop('placeholder')
if i >= datetime.now(tz).strftime("%Y-%m-%d"):
currDate = i
break
print("got dates")
return render_template('group_teach.html', cclass=cclass, all_stud_list=all_stud_list, dates=dates, currDate=currDate)
elif pl == 'homeroom':
homeroom = db.child("Users").child(
session['uid']).child("homeroom").get().val()
s += " " + homeroom # 912
return s
else:
return "no permission"
@ app.route('/upload/homeroom', methods=['GET', 'POST'])
def upload_homeroom():
if request.method == 'GET':
return render_template('uploadcsv.html', title="Homeroom List", url="/upload/homeroom")
elif request.method == 'POST':
try:
# get csv
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:
db.child("Homerooms").child(
classc).child(row['number']).set(row)
# 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 " + classc
@ app.route('/upload/stud_in_group', methods=['GET', 'POST'])
def upload_stud_in_group():
if request.method == 'GET':
return render_template('uploadcsv.html', title="Student in Group List", url="/upload/stud_in_group")
elif request.method == 'POST':
try:
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 row in csv_dict:
for h in headers:
db.child("Homerooms").child(classc).child(
row['number']).child("Classes").child(h).set(row[h])
db.child("Classes").child(h).child("Class").child(row[h]).child(
"Students").child(classc).update({str(row['number']): 0})
os.remove(filepath)
except Exception as e:
os.remove(filepath)
return "Error. Please try again\n("+str(e)+")"
return "Successfully uploaded " + classc
# @ app.route('/upload/rm_all_data_of_class', methods=['GET', "POST"])
# def rm_all_data_of_class():
# if request.method == 'GET':
# return render_template('uploadcsv.html', title="Remove all data of class", url="/upload/rm_all_data_of_class")
# elif request.method == 'POST':
# try:
# classc = request.form['classcode']
# db.child("Homerooms").child(classc).remove()
# except Exception as e:
# return "Error. Please try again\n("+str(e)+")"
# return "Successfully removed " + classc
@app.route('/logout', methods=['GET'])
def logout():
session.clear()
return redirect('/')
if __name__ == '__main__':
app.run(debug=True)

3
static/allpages.css Normal file
View file

@ -0,0 +1,3 @@
div.col .row .col {
border: 1px solid black;
}

BIN
static/loading.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 KiB

8
static/login.css Normal file
View file

@ -0,0 +1,8 @@
div.container {
text-align: center;
}
button {
width: 100%;
margin-top: 10px;
}

0
templates/admin.html Normal file
View file

View file

@ -0,0 +1,42 @@
<!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>Group_Teach_View</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">
</head>
<body>
<h1>Group_Teach_View</h1>
<h2>{{cclass['category']}}: {{cclass['class_id']}}: {{cclass['name']}}</h2>
<div class="col">
<div class="row title">
<div class="col">Class Code</div>
<div class="col">Number</div>
<div class="col">Name</div>
<div class="col">Eng Name</div>
<div class="col">Attendance</div>
</div>
{% if data != None %}
{% for homeroom in all_stud_list %}
{% for student in all_stud_list[homeroom] %}
<div class="row">
<div class="col">{{homeroom}}</div>
<div class="col">{{ student }}</div>
<div class="col">{{ all_stud_list[homeroom][student]['name'] }}</div>
<div class="col">{{ all_stud_list[homeroom][student]['eng_name'] }}</div>
<div class="col"><input type="checkbox" id="{{homeroom}}^{{student}}"></div>
</div>
{% endfor %}
{% endfor %}
{% endif %}
</div>
</body>
</html>

0
templates/homeroom.html Normal file
View file

53
templates/login.html Normal file
View file

@ -0,0 +1,53 @@
<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>Login</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">
</head>
<body>
<!-- login form center -->
<div class="container">
<div class="row">
<div class="col-md-4 offset-md-4">
<h1 class="text-center">Login</h1>
<form action="/" method="post">
<div class="form-group">
<label for="username">Username</label>
<input type="text" class="form-control" name="username" id="username" placeholder="Username">
</div>
<div class="form-group">
<label for="password">Password</label>
<input type="password" class="form-control" name="password" id="password"
placeholder="Password">
</div>
<button type="submit" class="btn btn-primary btn-block" onclick="loadingAnimation()">Login</button>
</form>
{% if error %}
<div class="alert alert-danger" role="alert">
Incorrect username or password
</div>
{% endif %}
</div>
</div>
</div>
<div id="loading" style="text-align:center; width:100%; display:none;"><img src="/static/loading.gif" alt=""
style="height:100%;" />
</div>
<!-- end login form center -->
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js"></script>
<script>
function loadingAnimation() {
$('.container').hide();
$('#loading').show();
}
</script>
</body>
</html>

40
templates/uploadcsv.html Normal file
View file

@ -0,0 +1,40 @@
<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>Login</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">
</head>
<body>
<!-- csv form center -->
<div class="container">
<div class="row">
<div class="col-md-4 offset-md-4">
<h1 class="text-center">Upload {{title}}</h1>
<!-- upload csv -->
<form action="{{url}}" method="post" enctype="multipart/form-data">
<!-- input class code -->
<div class="form-group">
<label for="classcode">Class Code</label>
<input type="text" class="form-control" id="classcode" name="classcode"
placeholder="Enter Class Code">
</div>
<div class="form-group">
<label for="csv">{{title}}</label>
<input type="file" class="form-control-file" id="csv" name="csv">
</div>
<button type="submit" class="btn btn-primary">Upload</button>
</form>
</div>
</div>
</div>
<!-- end csv form center -->
</body>
</html>