diff --git a/src/recommenderapp/app.py b/src/recommenderapp/app.py index f9744700e..3c70c6f00 100644 --- a/src/recommenderapp/app.py +++ b/src/recommenderapp/app.py @@ -8,7 +8,7 @@ import json import sys -from flask import Flask, jsonify, render_template, request +from flask import Flask, jsonify, render_template, request, session, redirect from flask_cors import CORS from search import Search from utils import beautify_feedback_data, send_email_to_user @@ -17,29 +17,116 @@ #pylint: disable=wrong-import-position from src.prediction_scripts.item_based import recommend_for_new_user #pylint: enable=wrong-import-position - +import db app = Flask(__name__) app.secret_key = "secret key" cors = CORS(app, resources={r"/*": {"origins": "*"}}) +# Connect to the database +db.connect() +# Initialize the database for users +db.mutation_query(''' + CREATE TABLE IF NOT EXISTS users ( + email varchar(500), + password varchar(500) + ) + ''') + +def get_user(): + """ + Returns the user's email if a user is logged in, otherwise returns none + """ + ret = 'None' + if 'email' in session: + # An email is in the session + ret = session['email'] + return ret @app.route("/") def landing_page(): """ - Renders the landing page. + Renders the landing page with the user. """ - return render_template("landing_page.html") + return render_template("landing_page.html", user=get_user()) +@app.route("/login") +def login_page(): + """ + Renders the login page. + """ + return render_template("login.html", user=get_user()) + +@app.route("/signup") +def signup_page(): + """ + Renders the signup page. + """ + return render_template("signup.html", user=get_user()) @app.route("/search_page") def search_page(): """ Renders the search page. """ - return render_template("search_page.html") + return render_template("search_page.html", user=get_user()) +@app.route('/processSignup', methods = ["POST","GET"]) +def processSignup(): + """ + Queries the database to see if the user already exists. If so it lets the javascript know + If not, the new user is added to the database + """ + ret = {} + # Below is how we create a dictionary of the data sent from the input form + form_fields = dict((key, request.form.getlist(key)[0]) for key in list(request.form.keys())) + # query to see if user in the database already + user_query = f"SELECT * FROM users where email=?" + result = db.select_query(user_query, (form_fields["email"],)) + result = result.fetchone() # get the first row + if result is None: + # if email is not in the database then we add it + add_user_query = f"INSERT INTO users (email, password) VALUES (?,?)" + db.mutation_query(add_user_query, (form_fields["email"], form_fields["password"])) + ret["success"] = 1 # send a success indicator back to the javascript side + # If user is in database, then send a failure indicator + else: + ret["success"] = 0 + + return ret + +@app.route('/processLogin', methods = ["POST","GET"]) +def processLogin(): + """ + Checks to see if the username name and password are valid + If so, the user is logged in via adding their email to the session data + Otherwise the javascript is told there was a mistake. + """ + ret = {} + # Below is how we create a dictionary of the data sent from the input form + form_fields = dict((key, request.form.getlist(key)[0]) for key in list(request.form.keys())) + # query to see if user in the database + user_query = f"SELECT * FROM users where email=? and password=?" + result = db.select_query(user_query, (form_fields["email"], form_fields["password"])) + result = result.fetchone() # get the first row + if result is None: + # if email and password is not in the database then we add it then send failure indicator + ret["success"] = 0 + + # If email and password is in the database we log the user in + else: + session['email'] = form_fields["email"] # add the email to the users session + ret["success"] = 1 + return ret + +@app.route('/logout') +def logout(): + """ + Logs the current user out by poping their email from current session + """ + session.pop('email', default=None) + return redirect('/') @app.route("/predict", methods=["POST"]) def predict(): @@ -97,7 +184,7 @@ def success(): """ Renders the success page. """ - return render_template("success.html") + return render_template("success.html", user=get_user()) if __name__ == "__main__": diff --git a/src/recommenderapp/db.py b/src/recommenderapp/db.py new file mode 100644 index 000000000..5f7f56fbc --- /dev/null +++ b/src/recommenderapp/db.py @@ -0,0 +1,29 @@ +# Reused code from previous project +import sqlite3 +from sqlite3 import Error +import os + +CON = None +def connect(): + ''' connect program to database file db.sqlite ''' + global CON + db_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', 'db.sqlite') + print(db_path) + try: + CON = sqlite3.connect(db_path, check_same_thread=False) + print("Connection to SQLite DB successful") + except Error as err: + print(f"The error '{err}' occurred when trying to connect to SQLite database") + + +def select_query(sql, args=()): + ''' select query to return items from database ''' + cur = CON.cursor() + return cur.execute(sql, args) + + +def mutation_query(sql, args=()): + ''' do a mutation on the database ''' + cur = CON.cursor() + cur.execute(sql, args) + CON.commit() \ No newline at end of file diff --git a/src/recommenderapp/static/login.css b/src/recommenderapp/static/login.css new file mode 100644 index 000000000..8dfbcad0f --- /dev/null +++ b/src/recommenderapp/static/login.css @@ -0,0 +1,16 @@ +#login-form { + margin: auto; /*so the form is in the center of it's container */ +} + +#Signup_text { + margin: auto; +} + +#login_alert { + margin: 0 auto; + padding-bottom: 5px; + padding-top: 5px; + margin-bottom: 10px; + margin-top: 10px; + display: none; +} \ No newline at end of file diff --git a/src/recommenderapp/static/login.js b/src/recommenderapp/static/login.js new file mode 100644 index 000000000..e737f09a3 --- /dev/null +++ b/src/recommenderapp/static/login.js @@ -0,0 +1,22 @@ +//Function for login in +function Login(){ + email = document.getElementById("inputemail").value + pass = document.getElementById("inputpassword").value + login_alert = document.getElementById("login_alert") + console.log(email) /* just for us to see outputs on the console for testing */ + console.log(pass) + $.ajax({ + url: "/processLogin", + type: 'POST', + data: {'email': email, 'password': pass, 'role': "user"}, + success:function(returned_data){ + if (returned_data['success'] === 1){ + window.location.href = "/" + } + else{ + login_alert.style.display = "flex"; + } + } + + }) +} diff --git a/src/recommenderapp/static/script.js b/src/recommenderapp/static/script.js index e3a08cc9e..32af9f3c4 100644 --- a/src/recommenderapp/static/script.js +++ b/src/recommenderapp/static/script.js @@ -1,5 +1,5 @@ $(document).ready(function () { - +console.log('hello') $(function () { $("#searchBox").autocomplete({ source: function (request, response) { @@ -127,6 +127,7 @@ $(document).ready(function () { // Function to handle Get Started button click function getStarted() { + console.log("Made it to this function!") // Navigate to the search page $("#loaderLanding").attr("class", "d-flex justify-content-center"); $("#centralDivLanding").hide(); diff --git a/src/recommenderapp/static/signup.css b/src/recommenderapp/static/signup.css new file mode 100644 index 000000000..9d4b052cf --- /dev/null +++ b/src/recommenderapp/static/signup.css @@ -0,0 +1,12 @@ +#signup-form { + margin: auto; /*so the form is in the center of it's container */ +} + +#failed_sign_in { + margin: 0 auto; + padding-bottom: 5px; + padding-top: 5px; + margin-bottom: 10px; + margin-top: 10px; + display: none; +} \ No newline at end of file diff --git a/src/recommenderapp/static/signup.js b/src/recommenderapp/static/signup.js new file mode 100644 index 000000000..f3dd919ec --- /dev/null +++ b/src/recommenderapp/static/signup.js @@ -0,0 +1,24 @@ +//Function for sign out +function Signup(){ + email = document.getElementById("inputemail").value + pass = document.getElementById("inputpassword").value + sign_alert = document.getElementById("failed_sign_in") + console.log(email) /* just for us to see outputs on the console for testing */ + console.log(pass) + $.ajax({ + url: "/processSignup", + type: 'POST', + data: {'email': email, 'password': pass, 'role': "user"}, // role will matter later + success:function(returned_data){ + if (returned_data['success'] === 1){ + // happens if the signup is valid + window.location.href = "/login" + } + else{ + // happens if the signup is not valid + //window.location.href = "/signup" + sign_alert.style.display = "flex"; + } + } + }) +} diff --git a/src/recommenderapp/templates/landing_page.html b/src/recommenderapp/templates/landing_page.html index 41c52539a..54fe8850a 100644 --- a/src/recommenderapp/templates/landing_page.html +++ b/src/recommenderapp/templates/landing_page.html @@ -1,54 +1,27 @@ - - -
- -
- Discover personalized movie recommendations by selecting up to 5 of your favorite films.
-
- Create a watchlist and have it conveniently sent to your email.
-
- Enjoy movies at your own pace, on your terms.
-
Made with ❤️ by PopcornPicks
- MIT License Copyright (c) 2023 PopcornPicks -
+ Discover personalized movie recommendations by selecting up to 5 of your favorite films.
+
+ Create a watchlist and have it conveniently sent to your email.
+
+ Enjoy movies at your own pace, on your terms.
+
Made with ❤️ by PopcornPicks
+ MIT License Copyright (c) 2023 PopcornPicks+{% endblock %} diff --git a/src/recommenderapp/templates/shared/layout.html b/src/recommenderapp/templates/shared/layout.html new file mode 100644 index 000000000..020a8fed0 --- /dev/null +++ b/src/recommenderapp/templates/shared/layout.html @@ -0,0 +1,45 @@ + + +
+ + +
+ + + + + + + + {% block extracss %}{% endblock %} + + + + + + + + + {% block extrajs %}{% endblock %} + +
+ + {% block extra_html_scripts %}{% endblock %} +