-
Notifications
You must be signed in to change notification settings - Fork 11
/
Copy pathmain.py
261 lines (215 loc) · 9.78 KB
/
main.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
import numpy as np
import pandas as pd
import os
import datetime as dt
from flask import Flask,render_template,url_for,request,g, flash, redirect
from werkzeug.utils import secure_filename
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
from flask_login import current_user, LoginManager, login_user, logout_user, UserMixin
from flask_admin import Admin, AdminIndexView
from flask_admin.contrib.sqla import ModelView
from flask_admin.model import BaseModelView
from sklearn.metrics import mean_absolute_error
from forms import LoginForm, RegisterForm
from config import Config
from scorer import Scorer
# PARAMETER
## Leaderboard parameter
limit_lb = 100 # Number of user showed at leaderboard table
greater_better = False # True if lowest score is the best; False if greatest score is the best
metric = mean_absolute_error #change the metric using sklearn function
scorer = Scorer(public_path = './master_key/public_key.csv',
private_path = './master_key/private_key.csv',
metric = metric) #change the metric using sklearn function
## Upload parameter
UPLOAD_FOLDER = 'submissions'
ALLOWED_EXTENSIONS = {'csv'} # only accept csv files
## FLASK configuration
app = Flask(__name__)
app.config['MAX_CONTENT_LENGTH'] = 2 * 1024 * 1024 # 2 Megabytes
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
app.config['SECRET_KEY'] = 'my'
app.config.from_object(Config)
## Database configuration
db = SQLAlchemy(app)
db.app = app
migrate = Migrate(app, db)
login = LoginManager(app)
# Database Model
@login.user_loader
def load_user(id):
return User.query.get(int(id))
class User(UserMixin, db.Model):
__tablename__ = "user"
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(64), index=True, unique=True)
password = db.Column(db.String(128)) ## Too lazy to make it hash
def __repr__(self):
return self.username
def check_password(self, password): ## Too lazy to make it hash
return self.password == password
class Submission(db.Model):
__tablename__ = "submission"
id = db.Column(db.Integer, primary_key=True)
timestamp = db.Column(db.DateTime, index=True, default=dt.datetime.now)
submission_type = db.Column(db.String(64))
user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
user = db.relationship('User')
score = db.Column(db.Float)
def __repr__(self):
return f'<User ID {self.user_id} score {self.score}>'
db.create_all()
# Admin
class MyAdminIndexView(AdminIndexView):
def is_accessible(self):
if current_user.is_authenticated:
return current_user.username == 'admin'
else:
False
def inaccessible_callback(self, name, **kwargs):
return redirect(url_for('home_page'))
class UserView(ModelView):
column_list = (User.id, 'username','password')
def is_accessible(self):
if current_user.is_authenticated:
return current_user.username == 'admin'
else:
False
def inaccessible_callback(self, name, **kwargs):
return redirect(url_for('home_page'))
class SubmissionView(ModelView):
column_list = (Submission.id, 'submission_type', 'user_id', 'user', 'timestamp', 'score')
def is_accessible(self):
if current_user.is_authenticated:
return current_user.username == 'admin'
else:
False
def inaccessible_callback(self, name, **kwargs):
return redirect(url_for('home_page'))
admin = Admin(app, index_view=MyAdminIndexView())
admin.add_view(UserView(User, db.session))
admin.add_view(SubmissionView(Submission, db.session))
# Leader Board
def get_leaderboard(greater_better, limit, submission_type = 'public'):
if greater_better:
score_agg = "MAX"
score_sorting = "DESC"
else:
score_agg = "MIN"
score_sorting = "ASC"
query = f"""
SELECT
user.username,
{score_agg}(submission.score) as score,
count(submission.id) as total_submission,
max(timestamp) as last_sub
FROM submission
LEFT JOIN user
ON user.id = submission.user_id
WHERE submission_type = '{submission_type}'
GROUP BY 1
ORDER BY 2 {score_sorting}, 4
LIMIT {limit}
"""
df = pd.read_sql(query,
db.session.bind)
return df
# Route
@app.route('/register', methods=['GET', 'POST'])
def register_page():
registration_status = request.args.get("registration_status", "")
reg_form = RegisterForm()
if request.method == 'POST':
### REGISTRATION
if reg_form.validate_on_submit():
user = User.query.filter_by(username=reg_form.username.data).first()
print(user)
if user is None: # only when user is not registered then proceed
print("HALOOO")
u = User(username=reg_form.username.data, password = reg_form.password.data)
db.session.add(u)
db.session.commit()
# flash('Congratulations, you are now a registered user!')
registration_status = f"Welcome {reg_form.username.data}, Please Login at HOME page"
return redirect(url_for('register_page', registration_status = registration_status))
else:
registration_status = "USER NAME ALREADY USED"
return redirect(url_for('register_page', registration_status = registration_status))
else:
registration_status = "ERROR VALIDATION"
print("ANEH")
return redirect(url_for('register_page', registration_status = registration_status))
if request.method == 'GET':
return render_template('register.html', reg_form = reg_form, registration_status = registration_status)
@app.route('/logout')
def logout():
logout_user()
print("log out success")
return redirect(url_for('home_page'))
def allowed_file(filename):
# checks if extension in filename is allowed
return '.' in filename and \
filename.rsplit('.', 1)[1] in ALLOWED_EXTENSIONS
@app.route('/', methods=['GET', 'POST'])
def home_page():
login_form = LoginForm()
login_status = request.args.get("login_status", "")
submission_status = request.args.get("submission_status", "")
leaderboard = get_leaderboard(greater_better = greater_better, limit = limit_lb, submission_type='public')
leaderboard_private = get_leaderboard(greater_better = greater_better, limit = limit_lb, submission_type='private')
if request.method == 'POST': # If upload file / Login
### LOGIN
if login_form.validate_on_submit():
print(f'Login requested for user {login_form.username.data}, remember_me={login_form.remember_me.data}')
user = User.query.filter_by(username=login_form.username.data).first()
if user is None: # USER is not registered
login_status = "User is not registered / Password does not match"
return redirect(url_for('home_page', login_status = login_status))
elif user.check_password(login_form.password.data): # Password True
print('True pass')
login_status = ""
login_user(user, remember=login_form.remember_me.data)
return redirect(url_for('home_page', login_status = login_status))
else: #WRONG PASSWORD
print('WRONG PASS')
login_status = "User is not registered / Password does not match"
return redirect(url_for('home_page', login_status = login_status))
login_status = ""
login_user(user, remember=login_form.remember_me.data)
return redirect(url_for('home_page', login_status = login_status))
### UPLOAD FILE
if 'uploadfile' in request.files.keys() and current_user.is_authenticated:
submission_file = request.files['uploadfile']
#throw error if extension is not allowed
if not allowed_file(submission_file.filename):
raise Exception('Invalid file extension')
if submission_file and allowed_file(submission_file.filename):
filename = secure_filename(submission_file.filename)
target_dir = os.path.join(app.config['UPLOAD_FOLDER'], str(current_user.id))
if not os.path.exists(target_dir):
os.makedirs(target_dir)
fullPath = os.path.join(app.config['UPLOAD_FOLDER'], str(current_user.id) , filename)
submission_file.save(fullPath)
submission_type = request.form.get('submission_type', "public")
result = scorer.calculate_score(submission_path = fullPath, submission_type = submission_type)
submission_status = result[0]
if submission_status == "SUBMISSION SUCCESS":
score = result[1]
score = round(score, 3)
s = Submission(user_id=current_user.id , score=score, submission_type = submission_type)
db.session.add(s)
db.session.commit()
print(f"submitted {score}")
submission_status = f"SUBMISSION SUCCESS | Score: {round(score,3)}"
return redirect(url_for('home_page', submission_status = submission_status))
return render_template('index.html',
leaderboard = leaderboard,
leaderboard_private = leaderboard_private,
login_form=login_form,
login_status=login_status,
submission_status=submission_status
)
if __name__ == '__main__':
app.debug = True
app.run(host = '0.0.0.0',port=5005)