diff --git a/User_MicroService_Group3/app.yaml b/User_MicroService_Group3/app.yaml new file mode 100644 index 0000000000000000000000000000000000000000..ab488dfb9077cfca361f84c8511c86b3ed935dbb --- /dev/null +++ b/User_MicroService_Group3/app.yaml @@ -0,0 +1,2 @@ +runtime: python312 +entrypoint: gunicorn -b :$PORT index:app \ No newline at end of file diff --git a/User_MicroService_Group3/app/__init__.py b/User_MicroService_Group3/app/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e5da06c31592e6410ec992cae27f65004ade98d6 --- /dev/null +++ b/User_MicroService_Group3/app/__init__.py @@ -0,0 +1,10 @@ +from flask import Flask + +from app.models import login + +app = Flask(__name__) + +from app import routes + +if __name__ == '__main__': + app.run(debug=True) \ No newline at end of file diff --git a/User_MicroService_Group3/app/config.py b/User_MicroService_Group3/app/config.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/User_MicroService_Group3/app/controllers/__init__.py b/User_MicroService_Group3/app/controllers/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..83fe4b03fbf1ea1097fdec730685170c3a35cc8d --- /dev/null +++ b/User_MicroService_Group3/app/controllers/__init__.py @@ -0,0 +1,3 @@ +from flask import Flask +from flask import Blueprint + diff --git a/User_MicroService_Group3/app/controllers/__pycache__/__init__.cpython-311.pyc b/User_MicroService_Group3/app/controllers/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5a4bfd8103bb4380305718ed59e96e027557a8a4 Binary files /dev/null and b/User_MicroService_Group3/app/controllers/__pycache__/__init__.cpython-311.pyc differ diff --git a/User_MicroService_Group3/app/controllers/__pycache__/changePasswordController.cpython-311.pyc b/User_MicroService_Group3/app/controllers/__pycache__/changePasswordController.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f2bccc2cdba24cef3aa5a38361740cb00752099f Binary files /dev/null and b/User_MicroService_Group3/app/controllers/__pycache__/changePasswordController.cpython-311.pyc differ diff --git a/User_MicroService_Group3/app/controllers/__pycache__/deleteProfileController.cpython-311.pyc b/User_MicroService_Group3/app/controllers/__pycache__/deleteProfileController.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8e06212bf94edd278c153db45bf9c8cb26a0fc10 Binary files /dev/null and b/User_MicroService_Group3/app/controllers/__pycache__/deleteProfileController.cpython-311.pyc differ diff --git a/User_MicroService_Group3/app/controllers/__pycache__/login.cpython-311.pyc b/User_MicroService_Group3/app/controllers/__pycache__/login.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ee02eac64b23cc7222f821324eb85aa9d76b8dc0 Binary files /dev/null and b/User_MicroService_Group3/app/controllers/__pycache__/login.cpython-311.pyc differ diff --git a/User_MicroService_Group3/app/controllers/__pycache__/loginController.cpython-311.pyc b/User_MicroService_Group3/app/controllers/__pycache__/loginController.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0ae33a0fab843db2a609b147bf8a5d6eaea25f24 Binary files /dev/null and b/User_MicroService_Group3/app/controllers/__pycache__/loginController.cpython-311.pyc differ diff --git a/User_MicroService_Group3/app/controllers/__pycache__/logoutController.cpython-311.pyc b/User_MicroService_Group3/app/controllers/__pycache__/logoutController.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..fef5e24b0dc447c671daa0656ba2d91c90e66b0a Binary files /dev/null and b/User_MicroService_Group3/app/controllers/__pycache__/logoutController.cpython-311.pyc differ diff --git a/User_MicroService_Group3/app/controllers/__pycache__/signupController.cpython-311.pyc b/User_MicroService_Group3/app/controllers/__pycache__/signupController.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d6315f975befa50cae416644dbce66638592358c Binary files /dev/null and b/User_MicroService_Group3/app/controllers/__pycache__/signupController.cpython-311.pyc differ diff --git a/User_MicroService_Group3/app/controllers/__pycache__/updateProfileController.cpython-311.pyc b/User_MicroService_Group3/app/controllers/__pycache__/updateProfileController.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d12100ee3869119656505afbb8d537567f89b91e Binary files /dev/null and b/User_MicroService_Group3/app/controllers/__pycache__/updateProfileController.cpython-311.pyc differ diff --git a/User_MicroService_Group3/app/controllers/changePasswordController.py b/User_MicroService_Group3/app/controllers/changePasswordController.py new file mode 100644 index 0000000000000000000000000000000000000000..516ca01a998aabcda4d2480ffa2b3bd2949d16c5 --- /dev/null +++ b/User_MicroService_Group3/app/controllers/changePasswordController.py @@ -0,0 +1,117 @@ +from flask import Blueprint, jsonify, request, session +from models.changePassword import check_old_password, set_new_password +import hashlib +import secrets +import hmac + +change_password_bp = Blueprint("change_password",__name__) + +@change_password_bp.route("/user/change_password", methods=["POST"]) +def change_password(): + + user_id = session.get("user_id") + + if user_id: + + if request.method == 'POST': + + #User data from front end + data = request.get_json() + email = data.get("email") + old_password = data.get("old_password") + new_password = data.get("new_password") + + new_encoded_password = generate_password_hash(new_password) + new_password_hash = new_encoded_password["hash"] + new_password_salt = new_encoded_password["salt"] + new_password_iterations = new_encoded_password["iterations"] + + + old_auth = { + "user_id" : user_id, + "email" : email, + "password": old_password + } + + #user_old_auth = check_old_password(old_auth) #Collect user data from database + + + + + old_auth_info, value = check_old_password(old_auth) #function returns certain columns collected from database + + if value == 1: #if user exists in database + + old_password_hash = old_auth_info.get("PasswordHash") + old_password_salt = old_auth_info.get("PasswordSalt") + old_password_iterations = old_auth_info.get("Iterations") + + + #password authentication + old_password_info = generate_password_hash(old_password) + is_correct = verify_password(old_password_info, old_password, old_password_salt, old_password_iterations, old_password_hash) + + if is_correct == True: + + new_auth = { + "user_id" : user_id, + "email" : email, + "password": new_password, + "hash": new_password_hash, + "salt": new_password_salt, + "iterations": new_password_iterations + } + + new_auth_info = set_new_password(new_auth) + + + + response_data = {"message":"Password is correct"} + return jsonify(new_auth_info, user_id) + + else: + response_data = {"error":"Old password is incorrect", "email": email} + return jsonify(response_data) + + else: + return {"error" : "Email does not exist"} + + + return {"error" : "null"} + + else: + return {"error" : "User not logged in"} + + + + + + +def generate_password_hash(password): + # Generate a 16-byte salt + salt = secrets.token_bytes(16) + # Define the number of iterations + iterations = 100000 + # Generate the hash using PBKDF2-HMAC-SHA-256 + hash = hashlib.pbkdf2_hmac('sha256', password.encode(), salt, iterations) + + # Return the salt, iterations, and hash, encoded in a way that can be stored in the database + return { + 'salt': salt.hex(), + 'iterations': iterations, + 'hash': hash.hex() + } + + +def verify_password(stored_password_info, submitted_password, salt, iterations, user_hash): + # Convert the stored salt back to bytes + salt = bytes.fromhex(salt) + # Use the same number of iterations as when the password was hashed + iterations = iterations + # Hash the submitted password with the stored salt and iterations + hash = hashlib.pbkdf2_hmac('sha256', submitted_password.encode(), salt, iterations) + + # Compare the newly generated hash with the stored hash + # Convert the generated hash to hex for comparison + + return hmac.compare_digest(hash.hex(), user_hash) \ No newline at end of file diff --git a/User_MicroService_Group3/app/controllers/deleteProfileController.py b/User_MicroService_Group3/app/controllers/deleteProfileController.py new file mode 100644 index 0000000000000000000000000000000000000000..c74dfe1faf87415a2fd52292becc0ff06484e5bb --- /dev/null +++ b/User_MicroService_Group3/app/controllers/deleteProfileController.py @@ -0,0 +1,33 @@ +from flask import Blueprint, jsonify, request, session +from models.deleteProfile import delete + +deleteProfile_bp = Blueprint("deleteProfile",__name__) + +@deleteProfile_bp.route("/user/deleteProfile", methods=["POST"]) +def deleteProfile(): + + user_id = session.get("user_id") + + if user_id: + + if request.method == 'POST': + + #User data from front end + data = request.get_json() + email = data.get("email") + + user_info = { + "email" : email, + "user_id" : user_id + } + + user = delete(user_info) #Collect user data from database + + + return jsonify(user, user_id) + + else: + return {"message" : "null"} + + else: + return {"error" : "User not logged in"} \ No newline at end of file diff --git a/User_MicroService_Group3/app/controllers/loginController.py b/User_MicroService_Group3/app/controllers/loginController.py new file mode 100644 index 0000000000000000000000000000000000000000..31313b3f1185ece1ffa16fc85b96b1344896dbb6 --- /dev/null +++ b/User_MicroService_Group3/app/controllers/loginController.py @@ -0,0 +1,91 @@ +from flask import Blueprint, jsonify, request, session +from models.login import fetch_user +from models.login import fetch_password +import hashlib +import secrets +import hmac + +login_bp = Blueprint("login",__name__) + +@login_bp.route("/login", methods=["POST"]) +def login(): + + if request.method == 'POST': + + #User data from front end + data = request.get_json() + email = data.get("email") + password = data.get("password") + + + + user = fetch_user(email) #Collect user data from database + + #User authentication + if user is not None: #If database found matching email the user entered + + user_email = user.get("Email") #User email from database + + + if user_email == email: #Checks if email returned from database is the same as what user entered + + auth = fetch_password(user_email) #function returns certain columns collected from database + + user_hash = auth.get("PasswordHash") + user_salt = auth.get("PasswordSalt") + user_iterations = auth.get("Iterations") + + + #password authentication + password_info = generate_password_hash(password) + is_correct = verify_password(password_info, password, user_salt, user_iterations, user_hash) + + if is_correct == True: + session["user_id"] = user.get("UserID") + response_data = {"message":"Login Sucessful", "email": email, "session" : session["user_id"]} + return jsonify(response_data) + + else: + response_data = {"message":"Email or password incorrect", "email": email} + return jsonify(response_data) + + + else: + return ("Email does not exist") + + else: + response_data = {"message":"Email does not exist", "email": email} + return jsonify(response_data) + + return {"message" : "null"} + + + +def generate_password_hash(password): + # Generate a 16-byte salt + salt = secrets.token_bytes(16) + # Define the number of iterations + iterations = 100000 + # Generate the hash using PBKDF2-HMAC-SHA-256 + hash = hashlib.pbkdf2_hmac('sha256', password.encode(), salt, iterations) + + # Return the salt, iterations, and hash, encoded in a way that can be stored in the database + return { + 'salt': salt.hex(), + 'iterations': iterations, + 'hash': hash.hex() + } + + +def verify_password(stored_password_info, submitted_password, salt, iterations, user_hash): + # Convert the stored salt back to bytes + salt = bytes.fromhex(salt) + # Use the same number of iterations as when the password was hashed + iterations = iterations + # Hash the submitted password with the stored salt and iterations + hash = hashlib.pbkdf2_hmac('sha256', submitted_password.encode(), salt, iterations) + + # Compare the newly generated hash with the stored hash + # Convert the generated hash to hex for comparison + + return hmac.compare_digest(hash.hex(), user_hash) \ No newline at end of file diff --git a/User_MicroService_Group3/app/controllers/logoutController.py b/User_MicroService_Group3/app/controllers/logoutController.py new file mode 100644 index 0000000000000000000000000000000000000000..c7ff97bca6d52edf2fd05e0c15ca25a2728a277c --- /dev/null +++ b/User_MicroService_Group3/app/controllers/logoutController.py @@ -0,0 +1,21 @@ +from flask import Blueprint, jsonify, request, json, session, redirect + + +logout_bp = Blueprint("logout",__name__) + +@logout_bp.route("/logout", methods=["POST"]) +def logout(): + + user_id = session.get("user_id") + + if user_id: + + if request.method == 'POST': + + session.pop("user_id", None) + return ({"message" : "Log out successful"}) + + else: + return {"error" : "null"} + else: + return {"error" : "User not logged in"} \ No newline at end of file diff --git a/User_MicroService_Group3/app/controllers/signupController.py b/User_MicroService_Group3/app/controllers/signupController.py new file mode 100644 index 0000000000000000000000000000000000000000..3876e7a869e0fb3bb5013a04ee00d6b45d48c906 --- /dev/null +++ b/User_MicroService_Group3/app/controllers/signupController.py @@ -0,0 +1,70 @@ +from flask import Blueprint, jsonify, request, json +from models.signup import new_user +import hashlib +import secrets +import hmac + +signup_bp = Blueprint("signup",__name__) + +@signup_bp.route("/signup", methods=["POST"]) +def signup(): + + if request.method == 'POST': + + #User data from front end + data = request.get_json() + email = data.get("email") + first_name = data.get("first_name") + last_name = data.get("last_name") + location = data.get("location") + gender = data.get("gender") + password = data.get("password") + encoded_password = generate_password_hash(password) + hash = encoded_password["hash"] + salt = encoded_password["salt"] + iterations = encoded_password["iterations"] + + if email.strip() != "": + + # Create a dictionary from user data + user_data = { + "email": email, + "first_name": first_name, + "last_name": last_name, + "location": location, + "gender": gender, + "password": password, + "hash": hash, + "salt": salt, + "iterations": iterations + } + + # Convert to JSON + json_user_data = json.dumps(user_data) + + + update = new_user(user_data) #Send user info to database + + return jsonify(update) + + else: + return {"message" : "email cannot be empty"} + + return {"message" : "null"} + + +#This function encrypts the user's password +def generate_password_hash(password): + # Generate a 16-byte salt + salt = secrets.token_bytes(16) + # Define the number of iterations + iterations = 100000 + # Generate the hash using PBKDF2-HMAC-SHA-256 + hash = hashlib.pbkdf2_hmac('sha256', password.encode(), salt, iterations) + + # Return the salt, iterations, and hash, encoded in a way that can be stored in the database + return { + 'salt': salt.hex(), + 'iterations': iterations, + 'hash': hash.hex() + } diff --git a/User_MicroService_Group3/app/controllers/updateProfileController.py b/User_MicroService_Group3/app/controllers/updateProfileController.py new file mode 100644 index 0000000000000000000000000000000000000000..faedd619b81621fbdef00903a2247b5812e348ff --- /dev/null +++ b/User_MicroService_Group3/app/controllers/updateProfileController.py @@ -0,0 +1,49 @@ +from flask import Blueprint, jsonify, request, json, session +from models.updateProfile import update_user +from models.updateProfile import fetch_user_info + +update_profile_bp = Blueprint("update",__name__) + +@update_profile_bp.route("/user/update", methods=["POST"]) +def update_profile(): + + user_id = session.get("user_id") + + if user_id: + + user_info = fetch_user_info(user_id) + print(jsonify(user_info)) + + if request.method == 'POST': + + #User data from front end + data = request.get_json() + email = data.get("email") + first_name = data.get("first_name") + last_name = data.get("last_name") + location = data.get("location") + gender = data.get("gender") + + + # Create a dictionary from user data + user_data = { + "user_id" : user_id, + "email": email, + "first_name": first_name, + "last_name": last_name, + "location": location, + "gender": gender, + } + + # Convert to JSON + json_user_data = json.dumps(user_data) + + + update = update_user(user_data) #Send user info to database + + return jsonify(update, user_id) + + else: + return {"error" : "null"} + else: + return {"error" : "User not logged in"} \ No newline at end of file diff --git a/User_MicroService_Group3/app/index.py b/User_MicroService_Group3/app/index.py new file mode 100644 index 0000000000000000000000000000000000000000..32fd79e7e8f7ebd21b299ee5237d86336e929f75 --- /dev/null +++ b/User_MicroService_Group3/app/index.py @@ -0,0 +1,42 @@ +from flask import Flask, redirect, url_for, request, render_template, make_response, session, abort +from flask_cors import CORS +from flask import jsonify +from controllers.loginController import login_bp +from controllers.signupController import signup_bp +from controllers.updateProfileController import update_profile_bp +from controllers.changePasswordController import change_password_bp +from controllers.deleteProfileController import deleteProfile_bp +from controllers.logoutController import logout_bp + + + +app = Flask(__name__) +CORS(app) + +app.secret_key = 'Group3' + +@app.route('/') +def index(): + return render_template("index.html") + + +@app.route("/hello/<int:score>") +def hello_user(score): + return render_template("hello.html", marks=score) + + +app.register_blueprint(login_bp) + +app.register_blueprint(signup_bp) + +app.register_blueprint(update_profile_bp) + +app.register_blueprint(change_password_bp) + +app.register_blueprint(deleteProfile_bp) + +app.register_blueprint(logout_bp) + + +if __name__ == '__main__': + app.run(debug=True, port=5000) \ No newline at end of file diff --git a/User_MicroService_Group3/app/models/__init__.py b/User_MicroService_Group3/app/models/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..d55ce4a0c8e0748e87cd3ecae1b6fe12294bdae3 --- /dev/null +++ b/User_MicroService_Group3/app/models/__init__.py @@ -0,0 +1,15 @@ +from flask import Flask +from flask_cors import CORS + + +#from app.models import models + +app = Flask(__name__) +CORS(app) + +#db = sqlAlchemy + +#from app import routes + +if __name__ == '__main__': + app.run(debug=True) \ No newline at end of file diff --git a/User_MicroService_Group3/app/models/__pycache__/__init__.cpython-311.pyc b/User_MicroService_Group3/app/models/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..dfb0366dfbe4ee46a4cd5603bac50bd5dcb0efcf Binary files /dev/null and b/User_MicroService_Group3/app/models/__pycache__/__init__.cpython-311.pyc differ diff --git a/User_MicroService_Group3/app/models/__pycache__/changePassword.cpython-311.pyc b/User_MicroService_Group3/app/models/__pycache__/changePassword.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3e2f696425d98b4acece898d09560e3b644ec81a Binary files /dev/null and b/User_MicroService_Group3/app/models/__pycache__/changePassword.cpython-311.pyc differ diff --git a/User_MicroService_Group3/app/models/__pycache__/database_connection.cpython-311.pyc b/User_MicroService_Group3/app/models/__pycache__/database_connection.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ee658c793e4a505d7b70e54b3c82b148e4f6561e Binary files /dev/null and b/User_MicroService_Group3/app/models/__pycache__/database_connection.cpython-311.pyc differ diff --git a/User_MicroService_Group3/app/models/__pycache__/deleteProfile.cpython-311.pyc b/User_MicroService_Group3/app/models/__pycache__/deleteProfile.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..11cd5e31a86ac49992cc243db920bc089e02298a Binary files /dev/null and b/User_MicroService_Group3/app/models/__pycache__/deleteProfile.cpython-311.pyc differ diff --git a/User_MicroService_Group3/app/models/__pycache__/login.cpython-311.pyc b/User_MicroService_Group3/app/models/__pycache__/login.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..54f0eb17fc5e099f4eaf6dcc17f1775c07a610e1 Binary files /dev/null and b/User_MicroService_Group3/app/models/__pycache__/login.cpython-311.pyc differ diff --git a/User_MicroService_Group3/app/models/__pycache__/models.cpython-311.pyc b/User_MicroService_Group3/app/models/__pycache__/models.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0c5497a917a5f33bfe0edde28b561ef47b6a7caf Binary files /dev/null and b/User_MicroService_Group3/app/models/__pycache__/models.cpython-311.pyc differ diff --git a/User_MicroService_Group3/app/models/__pycache__/signup.cpython-311.pyc b/User_MicroService_Group3/app/models/__pycache__/signup.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..94a888ae05aa3787387431d65168edf553a0a2cf Binary files /dev/null and b/User_MicroService_Group3/app/models/__pycache__/signup.cpython-311.pyc differ diff --git a/User_MicroService_Group3/app/models/__pycache__/updateProfile.cpython-311.pyc b/User_MicroService_Group3/app/models/__pycache__/updateProfile.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..43ec1e62b7e96678f2be3c7811088ea64c8e1774 Binary files /dev/null and b/User_MicroService_Group3/app/models/__pycache__/updateProfile.cpython-311.pyc differ diff --git a/User_MicroService_Group3/app/models/changePassword.py b/User_MicroService_Group3/app/models/changePassword.py new file mode 100644 index 0000000000000000000000000000000000000000..18d40df2c5a44a850a75212d058e6bee07d70a64 --- /dev/null +++ b/User_MicroService_Group3/app/models/changePassword.py @@ -0,0 +1,107 @@ +from flask import jsonify +import pyodbc +from models.database_connection import connect_db + + + +def check_old_password(data): + + try: #error handling + + connection = connect_db() + cursor = connection.cursor() + + email = data["email"] + user_id = data["user_id"] + + + + # Check if the email already exists + email_check_query = "SELECT COUNT(*) FROM dbo.User_table WHERE UserID = ?" + cursor.execute(email_check_query, user_id) + count = cursor.fetchone()[0] + + if count == 0: + return ({"Error" : "Email does not exist"}, 0) + + else: + + query = "SELECT t1.Email, t1.UserID, t2.Iterations, t2.PasswordHash, t2.PasswordSalt FROM dbo.User_table as t1 INNER JOIN dbo.AuthInfo as t2 ON t1.UserID = t2.UserID where t1.UserID= ?" + + cursor.execute(query, user_id) + + row = cursor.fetchone() + + columns = [column[0] for column in cursor.description] + user_data = dict(zip(columns, row)) + + #connection.close() + + return (user_data, 1) + + except pyodbc.Error as e: #more error handling + print(f"Database error in check_old_password: {e}") + connection.rollback() + return {"Error" : "Database error"} + + except Exception as e: #more error handling + print(f"Unexpected error occured in check_old_password: {e}") + connection.rollback() + return {"Error" : "Unexpected error"} + + finally: + if cursor: + cursor.close() + if connection: + connection.close() + + +def set_new_password(data): + + try: #error handling + + connection = connect_db() + cursor = connection.cursor() + + email = data["email"] + user_id = data["user_id"] + + + # + select_userID_query = "SELECT UserID from dbo.User_table where UserID = ?" + cursor.execute(select_userID_query, user_id) + UserID = cursor.fetchone()[0] + + + # + update_authinfo_query = '''UPDATE dbo.AuthInfo + SET PasswordHash = ?, PasswordSalt = ?, Iterations = ?, TempPlainText = ? + WHERE UserID = ?''' + + + cursor.execute(update_authinfo_query, (data["hash"], data["salt"], data["iterations"], data["password"], UserID)) + + connection.commit() + + + #connection.close() + + return {"Message" : "Password updated successfully"} + + + + except pyodbc.Error as e: #more error handling + print(f"Database error in set_new_password: {e}") + connection.rollback() + return {"Error" : "Database error"} + + except Exception as e: #more error handling + print(f"Unexpected error occured in set_new_password: {e}") + connection.rollback() + return {"Error" : "Unexpected error"} + + finally: + if cursor: + cursor.close() + if connection: + connection.close() \ No newline at end of file diff --git a/User_MicroService_Group3/app/models/database_connection.py b/User_MicroService_Group3/app/models/database_connection.py new file mode 100644 index 0000000000000000000000000000000000000000..8bad5678aab1e99f1324fa173b69a9a281ee1c74 --- /dev/null +++ b/User_MicroService_Group3/app/models/database_connection.py @@ -0,0 +1,14 @@ +import pyodbc + + +#Connect to database +def connect_db(): + + server = 'Chiamaka' + database = 'User_Management' + username = 'CHIAMAKA\amych' + password = '' + + connection_string = f'DRIVER={{SQL Server}};SERVER={server};DATABASE={database};UID={username};PWD={password};Trusted_Connection=yes;' + + return pyodbc.connect(connection_string) \ No newline at end of file diff --git a/User_MicroService_Group3/app/models/deleteProfile.py b/User_MicroService_Group3/app/models/deleteProfile.py new file mode 100644 index 0000000000000000000000000000000000000000..7972b969a1ba2a46cee56c5a76c0310f2be1b219 --- /dev/null +++ b/User_MicroService_Group3/app/models/deleteProfile.py @@ -0,0 +1,59 @@ +#from app import db +from flask import jsonify +import pyodbc +from models.database_connection import connect_db + + + +def delete(data): + + try: #error handling + + connection = connect_db() + cursor = connection.cursor() + + email = data["email"] + user_id = data["user_id"] + + # select user id from database + id_check_query = "SELECT UserID from dbo.User_table WHERE UserID= ?" + cursor.execute(id_check_query, user_id) + user_row = cursor.fetchone() + + if user_row: + userID = user_row[0] + else: + return {"Error": "User not found"} + + #delete from authinfo table first because of foreign key constraint + delete_authinfo_query = '''DELETE FROM dbo.AuthInfo WHERE UserID= ?''' + cursor.execute(delete_authinfo_query, userID) + + + #delete user info from user table + delete_user_query = '''DELETE FROM dbo.User_table WHERE UserID = ?''' + cursor.execute(delete_user_query, userID) + + + + + #commit changes to database if no errors + connection.commit() + + return {"message" : "Account successfully deleted"} + + except pyodbc.Error as e: #more error handling + print(f"Database error in delete: {e}") + connection.rollback() + return {"Error" : "Database error"} + + except Exception as e: #more error handling + print(f"Unexpected error occured in delete: {e}") + connection.rollback() + return {"Error" : "Unexpected error"} + + finally: + if cursor: + cursor.close() + if connection: + connection.close() \ No newline at end of file diff --git a/User_MicroService_Group3/app/models/login.py b/User_MicroService_Group3/app/models/login.py new file mode 100644 index 0000000000000000000000000000000000000000..6e344a768e8205c00e6d40e93df07c27e1deb941 --- /dev/null +++ b/User_MicroService_Group3/app/models/login.py @@ -0,0 +1,80 @@ +#from app import db +import pyodbc +from flask import jsonify +from models.database_connection import connect_db + +#Function to get user info +def fetch_user(email): + + try: #error handling + + connection = connect_db() + cursor = connection.cursor() + + query = "SELECT * FROM dbo.User_table where Email = ?" + cursor.execute(query, email) + + row = cursor.fetchone() #fetch data + + columns = [column[0] for column in cursor.description] + user_data = dict(zip(columns, row)) + + #connection.close() + + return user_data + + except pyodbc.Error as e: #error handling + print(f"Database error in fetch_user: {e}") + return None + + except Exception as e: #error handling + print(f"Unexpected error occured in fetch_user: {e}") + return None + + finally: + if cursor: + cursor.close() + if connection: + connection.close() + + + + + +def fetch_password(email): + + try: + + connection = connect_db() + cursor = connection.cursor() + + query = "SELECT t1.Email, t1.UserID, t2.Iterations, t2.PasswordHash, t2.PasswordSalt FROM dbo.User_table as t1 INNER JOIN dbo.AuthInfo as t2 ON t1.UserID = t2.UserID where Email= ?" + + cursor.execute(query, email) + + row = cursor.fetchone() + + if row is None: + return {"message" : "Email does not exist"} + + else: + columns = [column[0] for column in cursor.description] + user_data = dict(zip(columns, row)) + + #connection.close() + + return user_data + + except pyodbc.Error as e: + print(f"Database error in fetch_user: {e}") + return None + + except Exception as e: + print(f"Unexpected error occured in fetch_user: {e}") + return None + + finally: + if cursor: + cursor.close() + if connection: + connection.close() \ No newline at end of file diff --git a/User_MicroService_Group3/app/models/signup.py b/User_MicroService_Group3/app/models/signup.py new file mode 100644 index 0000000000000000000000000000000000000000..714741338ac7dfc19add5029d5813f105dbeae6d --- /dev/null +++ b/User_MicroService_Group3/app/models/signup.py @@ -0,0 +1,69 @@ +#from app import db +from flask import jsonify +import pyodbc +from models.database_connection import connect_db + + + +def new_user(data): + + try: #error handling + + connection = connect_db() + cursor = connection.cursor() + + email = data["email"] + + # Check if the email already exists + email_check_query = "SELECT COUNT(*) FROM dbo.User_table WHERE Email = ?" + cursor.execute(email_check_query, email) + count = cursor.fetchone()[0] + + if count > 0: + return {"Error": "Email already exists"} + + + #insert data into user table + insert_user_query = '''INSERT INTO dbo.User_table (Username, Email, First_Name, Last_Name, Tenure_Months, Location, Gender) +VALUES (?, ?, ?, ?, ?, ?, ?);''' + cursor.execute(insert_user_query, (data["first_name"], data["email"], data["first_name"], data["last_name"], " ", data["location"], data["gender"])) + + + UserID_query = "SELECT UserID FROM dbo.User_table WHERE Email= ?" + cursor.execute(UserID_query, email) + UserID = cursor.fetchone()[0] + + + #Insert password into authentication table + insert_authinfo_query = '''INSERT INTO dbo.AuthInfo (PasswordHash, PasswordSalt, Iterations, TempPlainText, UserID) +VALUES (?, ?, ?, ?, ?);''' + cursor.execute(insert_authinfo_query, (data["hash"], data["salt"], data["iterations"], data["password"], UserID)) + + + + + + + + + + #commit changes to database if no errors + connection.commit() + + return {"message" : "New user info added successfully"} + + except pyodbc.Error as e: #more error handling + print(f"Database error in new_user: {e}") + connection.rollback() + return {"Error" : "Database error"} + + except Exception as e: #more error handling + print(f"Unexpected error occured in new_user: {e}") + connection.rollback() + return {"Error" : "Unexpected error"} + + finally: + if cursor: + cursor.close() + if connection: + connection.close() \ No newline at end of file diff --git a/User_MicroService_Group3/app/models/updateProfile.py b/User_MicroService_Group3/app/models/updateProfile.py new file mode 100644 index 0000000000000000000000000000000000000000..0c70bedb121f72626f28135dc13b5d22fd962f08 --- /dev/null +++ b/User_MicroService_Group3/app/models/updateProfile.py @@ -0,0 +1,86 @@ +#from app import db +from flask import jsonify +import pyodbc +from models.database_connection import connect_db + + +def fetch_user_info(id): + + try: #error handling + + connection = connect_db() + cursor = connection.cursor() + + query = "SELECT * FROM dbo.User_table where UserID = ?" + cursor.execute(query, id) + + row = cursor.fetchone() #fetch data + + columns = [column[0] for column in cursor.description] + user_data = dict(zip(columns, row)) + + #connection.close() + + return user_data + + except pyodbc.Error as e: #error handling + print(f"Database error in fetch_user_info: {e}") + return None + + except Exception as e: #error handling + print(f"Unexpected error occured in fetch_user_info: {e}") + return None + + finally: + if cursor: + cursor.close() + if connection: + connection.close() + + + +def update_user(data): + + try: #error handling + + connection = connect_db() + cursor = connection.cursor() + + user_id = data["user_id"] + + #insert data into user table + update_user_query = '''UPDATE dbo.User_table + SET + Username= ?, + First_Name= ?, + Last_Name= ?, + Location= ?, + Gender= ? + WHERE + UserID= ?''' + + cursor.execute(update_user_query, (data["first_name"], data["first_name"], data["last_name"], data["location"], data["gender"], user_id)) + + + #commit changes to database if no errors + connection.commit() + + return {"message" : "Profile updated successfully"} + + + + except pyodbc.Error as e: #more error handling + print(f"Database error in update_user: {e}") + connection.rollback() + return {"Error" : "Database error"} + + except Exception as e: #more error handling + print(f"Unexpected error occured in update_user: {e}") + connection.rollback() + return {"Error" : "Unexpected error"} + + finally: + if cursor: + cursor.close() + if connection: + connection.close() \ No newline at end of file diff --git a/User_MicroService_Group3/app/run.py b/User_MicroService_Group3/app/run.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/User_MicroService_Group3/app/templates/index.html b/User_MicroService_Group3/app/templates/index.html new file mode 100644 index 0000000000000000000000000000000000000000..6207c5207b735653b32e6ad59ac7d969cdfab4eb --- /dev/null +++ b/User_MicroService_Group3/app/templates/index.html @@ -0,0 +1,6 @@ +<html> + <head></head> + <body> + <p>HELLO</p> + </body> +</html> \ No newline at end of file diff --git a/User_MicroService_Group3/requirements.txt b/User_MicroService_Group3/requirements.txt new file mode 100644 index 0000000000000000000000000000000000000000..6da6fc6ef7722e29986acb00b7f1caba9b9e5545 --- /dev/null +++ b/User_MicroService_Group3/requirements.txt @@ -0,0 +1,3 @@ +Flask==3.0.0 +gunicorn==21.2.0 +boto3==1.29.0 \ No newline at end of file