· 6 years ago · Jan 18, 2020, 06:54 PM
1#Enter 'python app.py' to launch webserver in terminal.
2
3#git add *
4#git commit
5#git push origin master
6
7#Commands used for launching db:
8#from app import db (after writing py) - imports our db to shell
9#db.create_all()
10#exit()
11
12
13#Imports flask from Flask class -- Flask is a web framework for Python.
14#Flask uses Jinja for templates; which is a web template engine.
15from flask import Flask, render_template, url_for, request, redirect, g
16from datetime import datetime
17import recommend
18import sqlite3
19
20
21#Python package which will be used to keep track of session ID's per user.
22import flask_login
23
24#Cursor fetches return results as tuples so need a function to convert to string;
25#used for login and database interactivity.
26def convertTuple(tup):
27 str = ''.join(tup)
28 return str
29
30#Sets up the app and database. Enter 'python app.py' to launch in terminal.
31app = Flask(__name__)
32DATABASE = 'test.db'
33
34#Secret key used for cookie/session info.
35#FIXME: Change this, placeholder key.
36app.secret_key = b'_5#y2L"F4Q8z\n\xec]/'
37
38
39#flask-login class;
40login_manager = flask_login.LoginManager()
41login_manager.init_app(app)
42
43
44class User(flask_login.UserMixin):
45 pass
46
47@login_manager.user_loader
48def user_loader(username):
49 conn = get_db()
50 c = conn.cursor()
51 c.execute("SELECT * FROM users WHERE username = '{}' ".format(username))
52
53 user = User()
54 user.id = username
55 return user
56
57
58#FIXME: Can probably remove this comment; request_loader seems to be identical to user_loader
59#but for API keys / header values (which I am not using)
60#will leave in for now.
61
62# @login_manager.request_loader
63# def request_loader(request):
64# username = request.form.get('username')
65#
66# user = User()
67# user.id = username
68
69# user.is_authenticated = request.form['password'] == users[username]['password']
70
71# return user
72
73
74
75
76
77
78
79
80
81
82
83# https://flask.palletsprojects.com/en/1.1.x/patterns/sqlite3/
84def get_db():
85 db = getattr(g, "_database", None)
86 if db is None:
87 db = g._database = sqlite3.connect(DATABASE)
88 return db
89
90@app.teardown_appcontext
91def close_connection(exception):
92 db = getattr(g, "_database", None)
93 if db is not None:
94 db.close()
95
96# Instantiate SVD Recommender..
97s = recommend.SVDRecommender(get_db)
98
99# Instantiate a random recommender.
100#r = recommend.RandomRecommender(get_db)
101
102# Instantiate KNN Recommender..
103k = recommend.KNNRecommender(get_db)
104
105#Sets up index route which will display index() function when route is visited.
106#index() function calls render_template method(which knows to check templates folder) to return our index.html.
107#methods enable us to POST and GET from the route (database).
108@app.route('/', methods=['POST', 'GET'])
109def index():
110 conn = get_db()
111 c = conn.cursor()
112 c.execute("SELECT * FROM books")
113 #FIXME: Using fetchmany currently to not load all 10k books onto webpage; need to fix how books load; possibly add pages.
114 allBooks = c.fetchall()[0:100]
115 userSession = flask_login.current_user.id
116 return render_template('index.html', allBooks = allBooks, userSession = userSession)
117
118@app.route('/results', methods=['POST', 'GET'])
119def results():
120 bookResults = s.get()
121 return render_template('results.html', bookResults = bookResults)
122
123@app.route('/knnresults', methods=['POST', 'GET'])
124def knnresults():
125 bookResults = k.get()
126 return render_template('results.html', bookResults = bookResults)
127
128#FIXME: Login will crash if the user is not logged in; look up how to restrict page if user session
129#not initalised.
130
131#FIXME: /login should probably return a template with this HTML and code; would make the code a lot cleaner.
132#https://docs.python.org/3.8/library/sqlite3.html for inputting variables into SQL query.
133@app.route('/login', methods=['GET', 'POST'])
134def login():
135 if request.method == 'GET':
136 return '''
137 <form action='login' method='POST'>
138 <input type='text' name='username' id='username' placeholder='username'/>
139 <input type='password' name='password' id='password' placeholder='password'/>
140 <input type='submit' name='submit'/>
141 </form>
142 '''
143
144 username = request.form['username']
145 c.execute("SELECT password FROM users WHERE username = '{}'".format(username))
146 passwordVerif = c.fetchone()
147 passwordVerif = convertTuple(passwordVerif)
148
149 if request.form['password']== passwordVerif:
150 user = User()
151 user.id = username
152 flask_login.login_user(user)
153 return redirect(url_for('protected'))
154
155 return 'Bad login'
156
157
158@app.route('/protected')
159@flask_login.login_required
160def protected():
161 return 'Logged in as: ' + flask_login.current_user.id
162
163
164#Post route which will be called on rating form submission (user five star input).
165@app.route('/rate/<int:book_id>', methods=['POST'])
166@flask_login.login_required
167def rate(book_id):
168 print("RATE")
169 conn = get_db()
170 c = conn.cursor()
171 rating = request.form.get('rating')
172 user_id = 1
173 #FIXME: Hardcoding this as 1 for now; will need to call the allBook id from index.html template somehow.
174
175 c.execute('SELECT * FROM ratings WHERE book_id == ' + str(book_id) + ' and user_id == ' + str(user_id))
176 check = c.fetchall()
177 print("CHECK {}".format(check))
178
179 if(len(check) < 1):
180 print("INSERT")
181 c.execute('INSERT INTO ratings (user_id, book_id, rating) VALUES (?, ?, ?)', (user_id, book_id, rating))
182 else:
183 print("UPDATE")
184 c.execute('UPDATE ratings set rating == ' + str(rating) + ' WHERE book_id == ' + str(book_id) + ' AND user_id == ' + str(user_id))
185
186 conn.commit()
187 return 'Ok'
188
189#Enables debug mode which displays errors on webpage.
190if __name__ == "__main__":
191 app.run(debug=True)