diff --git a/database.py b/database.py new file mode 100644 index 0000000..919bff0 --- /dev/null +++ b/database.py @@ -0,0 +1,79 @@ +from flask_mysqldb import MySQL + +class DB(object): + """docstring for DB""" + def __init__(self, app): + super (DB, self).__init__() + try: + self.mysql = MySQL(app) + self.cursor = None + self.connected = True + except: + self.connected = False + + def select(self, sql_string, args = None, quantity = "one"): + try: + self.cursor = self.mysql.connection.cursor() + self.cursor.execute(sql_string, args) + retult = 0 + if (quantity == "one"): + result = self.cursor.fetchone() + else: + result = self.cursor.fetchall() + self.cursor.close() + return (result) + except Exception as e: + print(e) + return -1 + + #used to call a database stored procedure + def callproc(self, procName, args, quantity = "one"): + try: + self.cursor = self.mysql.connection.cursor() + self.cursor.callproc(procName, args) + if (quantity == "one"): + result = self.cursor.fetchone() + else: + result = self.cursor.fetchall() + self.cursor.close() + return (result) + except Exception as e: + print(e) + return -1 + + #insert and update are duplicated methods for the sake of readability and in case we want to add specific behaviour to one of the operations + #they return the number of affected rows + def insert(self, sql_string, args = None): + try: + self.cursor = self.mysql.connection.cursor() + self.cursor.execute(sql_string, args) + result = self.cursor.rowcount + self.mysql.connection.commit() + self.cursor.close() + return (result) + except Exception as e: + print(e) + return -1 + + def update(self, sql_string, args = None): + try: + self.cursor = self.mysql.connection.cursor() + self.cursor.execute(sql_string, args) + result = self.cursor.rowcount + self.mysql.connection.commit() + self.cursor.close() + return (result) + except Exception as e: + print(e) + return -1 + + def close(self): + self.mysql.connection.close() + return (None) + +#implement the singleton logic for the database class +_DB = None + +def NewConexion(app): + global _DB + _DB = DB(app) \ No newline at end of file diff --git a/server.py b/server.py index b062f29..1e53931 100644 --- a/server.py +++ b/server.py @@ -1,9 +1,10 @@ from flask import Flask,render_template,request,redirect, url_for, make_response -from flask_mysqldb import MySQL +#from flask_mysqldb import MySQL from flask_socketio import SocketIO, send, emit from tools import * from functools import wraps import random +import database app = Flask(__name__) app.config.from_object('config.Config') @@ -14,8 +15,6 @@ app.config['MYSQL_PASSWORD'] = 'Game_server' #change this password to your MySQL password for root@localhost app.config['MYSQL_DB'] = 'Game_server' -mysql = MySQL(app) - GAME_ID_SNAKE = 1 GAME_ID_CONNECT4 = 2 @@ -69,16 +68,17 @@ def Register(): return render_template('register.html', error = error) #Valid input handling - cur=mysql.connection.cursor() - _sql = "select * from Login_Credentials where PlayerID = '{0}'" - cur.execute(_sql.format(email)) - data=cur.fetchall() + data = database._DB.select("SELECT PlayerID FROM Login_Credentials WHERE PlayerID = %s;", (email,), "all") + if (data == -1): + return errorDB, 500 if(len(data) is 0): error = None - cur.execute("INSERT INTO Player_Profile(PlayerID,firstName,lastName) VALUES(%s,%s,%s)",(email,firstName,lastName)) - cur.execute("INSERT INTO Login_Credentials VALUES(%s,MD5(%s))",(email,password)) - mysql.connection.commit() - cur.close() + res = database._DB.insert("INSERT INTO Player_Profile(PlayerID,firstName,lastName) VALUES (%s,%s,%s);", (email, firstName, lastName)) + if (res == -1): + return errorDB, 500 + res = database._DB.insert("INSERT INTO Login_Credentials VALUES(%s,MD5(%s));", (email, password)) + if (res == -1): + return errorDB, 500 return redirect(url_for('Login')) else: error = 'Email already registered!' @@ -90,25 +90,24 @@ def Login(): if request.method=='POST': email=request.form['loginEmail'] password=request.form['loginPassword'] - cur=mysql.connection.cursor() - _sql = "select md5('{0}')" - cur.execute(_sql.format(password)) - enc_string=cur.fetchall() - _sql = "select password from Login_Credentials where PlayerID = '{0}'" - cur.execute(_sql.format(email)) - stored=cur.fetchall() + enc_string = database._DB.select("SELECT MD5(%s);", (password,), "all") + if (enc_string == -1): + return errorDB, 500 + stored = database._DB.select("SELECT password FROM Login_Credentials WHERE PlayerID = %s;", (email,), "all") + if (stored == -1): + return errorDB, 500 if(len(stored) is 0): error = 'Email not found!' else: if(enc_string==stored): logged_in_users.append(email) #get the playerID - cur.callproc("fullName", (email,)) - res = cur.fetchone() + res = database._DB.callproc("fullName", (email,)) + if res == -1: + return errorDB, 500 resp = make_response(redirect(url_for('Index'))) resp.set_cookie('email',email) resp.set_cookie('fullName', res[0]) - cur.close() return resp else: error = 'Invalid password' @@ -124,24 +123,21 @@ def Logout(): logged_in_users.remove(email) return resp -@app.route('/profile') +@app.route('/profile', methods=['GET', 'POST']) @login_required def Profile(): error = None email = request.cookies.get('email') - cur=mysql.connection.cursor() if request.method=='POST': firstName = request.form['firstName'] lastName = request.form['lastName'] - _sql = "update Player_Profile set firstName='{0}', lastName='{1}' where PlayerID = '{2}'" - cur.execute(_sql.format(firstName,lastName,email)) - mysql.connection.commit() - - _sql = "select * from Player_Profile where PlayerID = '{0}'" - cur.execute(_sql.format(email)) - values = cur.fetchall() - cur.close() - (user_email,firstName,lastName,cash,gold) = values[0] + res = database._DB.update("UPDATE Player_Profile SET firstName = %s, lastName = %s WHERE PlayerID = %s;", (firstName,lastName,email)) + if (res == -1): + return errorDB, 500 + res = database._DB.select("SELECT PlayerID, firstName, lastName, Cash, Gold FROM Player_Profile WHERE PlayerID = %s;", (email,)) + if (res == -1): + return errorDB, 500 + (user_email,firstName,lastName,cash,gold) = res name = firstName+" "+lastName resp = make_response(render_template('profile.html', email=user_email, name=name, cash=cash, gold=gold)) #reset the fullName cookie if it has been updated @@ -152,43 +148,40 @@ def Profile(): @app.route('/leaderboard') @login_required def Leaderboard(): - cur = mysql.connect.cursor() - _sql = "select @rank:=@rank+1 as _rank, firstName, lastName, Cash from Player_Profile p, (select @rank := 0) r order by Cash desc" - cur.execute(_sql) - values = cur.fetchall() + _sql = "SELECT @rank:=@rank+1 as _rank, firstName, lastName, Cash FROM Player_Profile p, (select @rank := 0) r ORDER BY Cash DESC;" + values = database._DB.select(_sql, None, "all") + if (values == -1): + return errorDB, 500 cash_leaderboard = [list(x) for x in values] - _sql = "select @rank:=@rank+1 as _rank, firstName, lastName, Gold from Player_Profile p, (select @rank := 0) r order by Gold desc" - cur.execute(_sql) - values = cur.fetchall() + _sql = "SELECT @rank:=@rank+1 as _rank, firstName, lastName, Gold FROM Player_Profile p, (select @rank := 0) r ORDER BY Gold DESC;" + gold_leaderboard = database._DB.select(_sql, None, "all") + if (gold_leaderboard == -1): + return errorDB, 500 gold_leaderboard = [list(x) for x in values] - cur.close() return render_template('leaderboard.html',cash_leaderboard=cash_leaderboard, gold_leaderboard=gold_leaderboard) @app.route('/history') @login_required def PlayerHistory(): email = request.cookies.get('email') - cur = mysql.connect.cursor() - _sql = "select @rank:=@rank+1 as _rank, Cash, Gold from Player_History p, (select @rank := 0) r where PlayerID='{0}' and GameID={1} order by Cash desc" - cur.execute(_sql.format(email,GAME_ID_SNAKE)) - values = cur.fetchall() + _sql = "SELECT @rank:=@rank+1 AS _rank, Cash, Gold FROM Player_History p, (SELECT @rank := 0) r WHERE PlayerID=%s AND GameID=%s ORDER BY Cash DESC;" + values = database._DB.select(_sql, (email, GAME_ID_SNAKE), "all") + if (values == -1): + return errorDB, 500 snake_history = [list(x) for x in values] - _sql = "select @rank:=@rank+1 as _rank, Cash, Gold from Player_History p, (select @rank := 0) r where PlayerID='{0}' and GameID={1} order by Cash desc" - cur.execute(_sql.format(email,GAME_ID_CONNECT4)) - values = cur.fetchall() + _sql = "SELECT @rank:=@rank+1 AS _rank, Cash, Gold FROM Player_History p, (SELECT @rank := 0) r WHERE PlayerID=%s AND GameID=%s ORDER BY Cash DESC;" + values = database._DB.select(_sql, (email, GAME_ID_CONNECT4), "all") connect4_history = [list(x) for x in values] - cur.close() return render_template('playerHistory.html',snake_history=snake_history, connect4_history=connect4_history) @app.route('/shop') @login_required def Shop(): - cur = mysql.connect.cursor() - _sql = "select * from Perks_Available" - cur.execute(_sql) - values = cur.fetchall() + _sql = "SELECT * from Perks_Available;" + values = database._DB.select(_sql, None, "all") + if (values == -1): + return errorDB, 500 perks = [list(x) for x in values] - cur.close() return render_template('store.html', perks = perks) @app.route('/index.html') @@ -207,44 +200,40 @@ def MiniGames(): @app.route('/waitingPage.html') @login_required def Waiting(): - email = request.cookies.get('email') game_id = int(request.args.get('game_id')) - - cur=mysql.connection.cursor() - _sql = "select GameID from Players_in_Game where GameID = '{0}'" - cur.execute(_sql.format(game_id)) - stored=cur.fetchall() - + _sql = "SELECT GameID FROM Players_in_Game WHERE GameID = %s;" + stored = database._DB.select(_sql, (game_id,), "all") + if (stored == -1): + return errorDB, 500 if(len(stored)%2==0): - - _sql = "select No_of_rooms from Mini_Game where GameID = '{0}'" - cur.execute(_sql.format(game_id)) - stored=cur.fetchall() - curr_rooms = stored[0][0] + _sql = "SELECT No_of_rooms FROM Mini_Game WHERE GameID = %s;" + stored = database._DB.select(_sql, (game_id,)) + if (stored == -1): + return errorDB, 500 + curr_rooms = stored[0] curr_rooms = curr_rooms + 1 - _sql = "update Mini_Game set No_of_rooms = '{0}' where GameID = '{1}'" - cur.execute(_sql.format(curr_rooms,game_id)) - _sql = "insert into Players_in_Game values('{0}','{1}','{2}')" - cur.execute(_sql.format(email, game_id, curr_rooms)) - mysql.connection.commit() + _sql = "UPDATE Mini_Game SET No_of_rooms = %s WHERE GameID = %s;" + res = database._DB.update(_sql, (curr_rooms, game_id)) + if (res == -1): + return errorDB, 500 + _sql = "INSERT INTO Players_in_Game VALUES(%s,%s,%s);" + res = database._DB.insert(_sql, (email, game_id, curr_rooms)) return render_template('waitingPage.html', email=email, game_id=game_id) - else: - - _sql = "select No_of_rooms from Mini_Game where GameID = '{0}'" - cur.execute(_sql.format(game_id)) - stored=cur.fetchall() - curr_rooms = stored[0][0] - _sql = "insert into Players_in_Game values('{0}','{1}','{2}')" - cur.execute(_sql.format(email, game_id, curr_rooms)) - mysql.connection.commit() - + _sql = "SELECT No_of_rooms FROM Mini_Game WHERE GameID = %s;" + stored = database._DB.select(_sql, (game_id,)) + if (stored == -1): + return errorDB, 500 + curr_rooms = stored[0] + _sql = "INSERT INTO Players_in_Game VALUES(%s,%s,%s);" + res = database._DB.insert(_sql, (email, game_id, curr_rooms)) + if (res == -1): + return errorDB, 500 if game_id == GAME_ID_SNAKE: snakePartners[email]=snakeWaitingSid[0] snakePartners[snakeWaitingSid[0]]=email return redirect(url_for('SAL')) - elif game_id == GAME_ID_CONNECT4: c4pairs[email] = c4WaitingSid[0] c4pairs[c4WaitingSid[0]] = email @@ -254,6 +243,9 @@ def Waiting(): @login_required def SAL(): email = request.cookies.get('email') + #redirect to index if the email is not in snakePartners + if email not in snakePartners: + return redirect(url_for("Logout")) player2 = GetFullName(snakePartners[email]) player1 = request.cookies.get("fullName") return render_template('snakegame.html', player1=player1, player2=player2) @@ -262,6 +254,9 @@ def SAL(): @login_required def Connect4(): email = request.cookies.get('email') + #redirect to index if the email is not in the dictionnary + if email not in c4pairs: + return redirect(url_for("Logout")) paired_email = GetFullName(c4pairs[email]) fullName = request.cookies.get("fullName") if email in c4WaitingSid: @@ -272,7 +267,6 @@ def Connect4(): # Socket IO functionality @socketio.on('waiting_id', namespace='/private') def receive_waiting_user(data): - if int(data['game_id']) == GAME_ID_SNAKE: snakeWaitingSid.clear() snakeWaitingSid.append(data['player']) @@ -300,39 +294,40 @@ def leave_waiting(arr): def send_move(arr): email = request.cookies.get('email') if(arr[0] == 'check2x'): - cur=mysql.connection.cursor() arr.clear() - _sql = "select Quantity from Owned_Perk where PlayerID = '{0}' and PerkID = '{1}'" - cur.execute(_sql.format(email,1)) - stored=cur.fetchall() + _sql = "SELECT Quantity FROM Owned_Perk WHERE PlayerID = %s AND PerkID = %s;" + stored = database._DB.select(_sql, (email, 1), "all") + if (stored == -1): + return errorDB, 500 if(len(stored)==0 or stored[0][0]==0): arr.append('twoxFailed') else: newVal = stored[0][0] - 1 - # print(newVal) - _sql = "update Owned_Perk set Quantity='{0}' where PlayerID = '{1}' and PerkID = {2}" - cur.execute(_sql.format(newVal,email,1)) - mysql.connection.commit() + _sql = "UPDATE Owned_Perk SET Quantity=%s WHERE PlayerID = %s AND PerkID = %s;" + res = database._DB(_sql, (newVal, email, 1)) + if (res == -1): + return errorDB, 500 arr.append('twoxPassed') emit('getMove',arr,room=snakeUsers[email]) elif(arr[0] == 'checkHeadStart'): player1 = True if(arr[1]=='p2'): player1 = False - cur=mysql.connection.cursor() arr.clear() arr.append(player1) - _sql = "select Quantity from Owned_Perk where PlayerID = '{0}' and PerkID = '{1}'" - cur.execute(_sql.format(email,2)) - stored=cur.fetchall() + _sql = "SELECT Quantity FROM Owned_Perk WHERE PlayerID = %s AND PerkID = %s;" + stored = database._DB.select(_sql, (email, 2), "all") + if (stored == -1): + return errorDB, 500 if(len(stored)==0 or stored[0][0]==0): arr.append('headStartFailed') else: newVal = stored[0][0] - 1 print(newVal) - _sql = "update Owned_Perk set Quantity='{0}' where PlayerID = '{1}' and PerkID = {2}" - cur.execute(_sql.format(newVal,email,2)) - mysql.connection.commit() + _sql = "UPDATE Owned_Perk SET Quantity= %s WHERE PlayerID = %s AND PerkID = %s;" + res = database._DB.update(_sql, (newVal, email, 2)) + if (res == -1): + return errorDB, 500 arr.append('headStartPassed') arr.append(random.randint(1,11)) emit('getMove',arr,room=snakeUsers[email]) @@ -345,18 +340,19 @@ def send_move(arr): def running_game(data): if data == "twoXMultiplier": email = request.cookies.get('email') - cur=mysql.connection.cursor() - _sql = "select Quantity from Owned_Perk where PlayerID = '{0}' and PerkID = '{1}'" - cur.execute(_sql.format(email,1)) - stored=cur.fetchall() + _sql = "SELECT Quantity FROM Owned_Perk WHERE PlayerID = %s AND PerkID = %s;" + stored = database._DB.select(_sql, (email, 1), "all") + if (stored == -1): + return errorDB, 500 if(len(stored)==0 or stored[0][0]==0): emit('game_state',"fail",room=c4users[email]) else: newVal = stored[0][0] - 1 print(newVal) - _sql = "update Owned_Perk set Quantity='{0}' where PlayerID = '{1}' and PerkID = {2}" - cur.execute(_sql.format(newVal,email,1)) - mysql.connection.commit() + _sql = "UPDATE Owned_Perk SET Quantity='{0}' WHERE PlayerID = %s AND PerkID = %s;" + res = database._DB.update(_sql, (newVal, email, 1)) + if (res == -1): + return errorDB, 500 emit('game_state',"passed",room=c4users[email]) else: email = data['user'] @@ -366,59 +362,68 @@ def running_game(data): @socketio.on('update_database', namespace='/private') def update_db(arr): email = request.cookies.get('email') - cur=mysql.connection.cursor() - _sql = "select GameID,RoomID from Players_in_Game where PlayerID = '{0}'" + _sql = "SELECT GameID,RoomID FROM Players_in_Game WHERE PlayerID = %s;" + stored = database._DB.select(_sql, (email,)) cur.execute(_sql.format(email)) stored=cur.fetchall() - gameID = stored[0][0] - roomID = stored[0][1] - _sql = "insert into Player_History values ('{0}',{1},{2},{3},{4});" - cur.execute(_sql.format(email,gameID,roomID,arr[0],arr[1])) - _sql = "delete from Players_in_Game where PlayerID = '{0}'" - cur.execute(_sql.format(email)) - _sql = "select Cash,Gold from Player_Profile where PlayerID = '{0}'" - cur.execute(_sql.format(email)) - stored = cur.fetchall() - cash = stored[0][0] - gold = stored[0][1] + gameID = stored[0] + roomID = stored[1] + _sql = "INSERT INTO Player_History VALUES (%s,%s,%s,%s,%s);" + args = (email, gameID, roomID, arr[0], arr[1]) + res = database._DB.insert(_sql, args) + if (res == -1): + return errorDB, 500 + _sql = "DELETE FROM Players_in_Game WHERE PlayerID = %s;" + res = database._DB.delete(_sql, (email,)) + if (res == -1): + return errorDB, 500 + _sql = "SELECT Cash,Gold FROM Player_Profile WHERE PlayerID = %s;" + stored = database._DB.select(_sql, (email,)) + cash = stored[0] + gold = stored[1] cash += arr[0] gold += arr[1] - _sql = "update Player_Profile set Cash={0}, Gold={1} where PlayerID='{2}'" - cur.execute(_sql.format(cash,gold,email)) - mysql.connection.commit() - cur.close() + _sql = "UPDATE Player_Profile SET Cash=%s, Gold=%s WHERE PlayerID=%s;" + res = database._DB.update(_sql, (cash, gold, email)) + if (res == -1): + return errorDB, 500 @socketio.on('buyPerk', namespace='/private') def buyPerk(arr): email = request.cookies.get('email') - cur=mysql.connection.cursor() if(arr[0]=='getAvailableGold'): - _sql = "select Gold from Player_Profile where PlayerID = '{0}'" - cur.execute(_sql.format(email)) - stored = cur.fetchall() - gold = stored[0][0] + _sql = "SELECT Gold FROM Player_Profile WHERE PlayerID = %s;" + stored = database._DB.select(_sql, (email,)) + if (stored == -1): + return errorDB, 500 + gold = stored[0] arr.clear() arr.append('goldAvailable') arr.append(gold) emit('perkResult',arr,room=request.sid) else: - _sql = "select Quantity from Owned_Perk where PlayerID = '{0}' and PerkID = {1}" - # print('HERE',_sql.format(email,arr[1])) - cur.execute(_sql.format(email,arr[1])) - stored=cur.fetchall() - # print(stored) + _sql = "SELECT Quantity FROM Owned_Perk WHERE PlayerID = %s AND PerkID = %s;" + stored = database._DB.select(_sql, (email, arr[1])) if(len(stored) is 0): quantity = 1 - _sql = "insert into Owned_Perk values('{0}',{1},{2})" - cur.execute(_sql.format(email,arr[1],quantity)) + _sql = "INSERT INTO Owned_Perk VALUES(%s,%s,%s);" + args = (email, arr[1], quantity) + res = database.db.insert(_sql, args) + if (res == -1): + return errorDB, 500 else: - quantity = stored[0][0] + quantity = stored[0] quantity = quantity + 1 - _sql = "update Owned_Perk set Quantity ={0} where PlayerID = '{1}' and PerkID = {2}" - cur.execute(_sql.format(quantity,email,arr[1])) - _sql = "update Player_Profile set Gold ={0} where PlayerID = '{1}'" - cur.execute(_sql.format(arr[2],email)) - mysql.connection.commit() + _sql = "UPDATE Owned_Perk SET Quantity = %s WHERE PlayerID = %s AND PerkID = %s;" + res = database._DB.update(_sql, (quantity, email, arr[1])) + if (res == -1): + return errorDB, 500 + _sql = "UPDATE Player_Profile SET Gold = %s WHERE PlayerID = %s;" + res = database._DB.update(_sql, (arr[2], email)) + if (res == -1): + return errorDB, 500 if __name__ == "__main__": + #initiate database connexion + database.NewConexion(app) socketio.run(app) \ No newline at end of file diff --git a/tools.py b/tools.py index 7ccef4a..f685228 100644 --- a/tools.py +++ b/tools.py @@ -1,12 +1,15 @@ from flask_mysqldb import MySQL -from server import mysql +#from server import mysql +import database + +#default error message in case an error occurs with the database +errorDB = "Database unreachable" #get a user full name by their id def GetFullName(id): #get opponent full name - cur=mysql.connection.cursor() - cur.callproc("fullName", (id,)) - res=cur.fetchone() - fullName = res[0] - cur.close - return fullName \ No newline at end of file + res = database._DB.callproc("fullName", (id,)) + if (res == -1): + return "ERROR DATABASE" + fullName = res[0] + return fullName \ No newline at end of file