From 137bb1936b8d60d0746470a9a47ecd6db6bf962e Mon Sep 17 00:00:00 2001 From: Faisal Fawad Date: Sat, 2 Nov 2024 21:13:58 -0400 Subject: [PATCH] Skeleton OAuth implementation --- imaginate_api/config.py | 5 ++++- imaginate_api/schemas/user_info.py | 18 +++++++++++++++--- imaginate_api/user/routes.py | 10 ++++------ 3 files changed, 23 insertions(+), 10 deletions(-) diff --git a/imaginate_api/config.py b/imaginate_api/config.py index a8f8222..2bbb56c 100644 --- a/imaginate_api/config.py +++ b/imaginate_api/config.py @@ -29,9 +29,12 @@ class Config: "token_url": "https://accounts.google.com/o/oauth2/token", "user_info": { "url": "https://www.googleapis.com/oauth2/v3/userinfo", - "data": lambda json: {"email": json["email"]}, + "data": lambda json: {"email": json["email"], "id": json["sub"]}, }, "scopes": ["https://www.googleapis.com/auth/userinfo.email"], } } + BASE_URL = ( + "https://playimaginate.com" if DB_ENV == "prod" else "http://127.0.0.1:5000" + ) TESTING = False diff --git a/imaginate_api/schemas/user_info.py b/imaginate_api/schemas/user_info.py index bcffb5b..a621190 100644 --- a/imaginate_api/schemas/user_info.py +++ b/imaginate_api/schemas/user_info.py @@ -22,7 +22,7 @@ def is_active(self): @property def is_anonymous(self): - return True # Always return True based on spec + return False # Always return False based on specification def get_id(self): return str(self.user_data["_id"]) @@ -37,15 +37,27 @@ def deactivate_user(self): COLLECTION.update_one({"_id": self.user_data["_id"]}, {"$set": {"active": False}}) self.user_data["active"] = False - # Create or find user by data -> email @classmethod - def find_or_create_user(cls, data): + def find_or_create_user(cls, data, provider=None): + # Primary identifier: Try to find the existing user by using the unique ID from the provider + if provider: + existing_user = COLLECTION.find_one({f"{provider}_id": data["id"]}) + if existing_user: + return User(user_data=existing_user) + + # Secondary identifier: Try to find the existing user by using the email from the provider existing_user = COLLECTION.find_one({"email": data["email"]}) if existing_user: + if provider: + COLLECTION.update_one( + {"_id": existing_user["_id"]}, {"$set": {f"{provider}_id": data["id"]}} + ) return User(user_data=existing_user) + # If no user is found, create a new one data["authenticated"] = False data["active"] = True + data[f"{provider}_id"] = data.pop("id") new_user = COLLECTION.insert_one(data) return User.get(new_user.inserted_id) diff --git a/imaginate_api/user/routes.py b/imaginate_api/user/routes.py index 8ab3ecc..1f375b1 100644 --- a/imaginate_api/user/routes.py +++ b/imaginate_api/user/routes.py @@ -7,14 +7,13 @@ import requests bp = Blueprint("user", __name__) -reroute_url = "index" # Currently set to index, but will be changed to imaginate home page in the future # Initiates the authorization process with the specified provider @bp.route("/authorize/") def user_authorize(provider): if not current_user.is_anonymous: - return redirect(url_for("index")) + return redirect(current_app.config["BASE_URL"]) provider_data = current_app.config["AUTH_PROVIDERS"].get(provider) if not provider_data: @@ -24,7 +23,6 @@ def user_authorize(provider): ) session["oauth_state"] = secrets.token_urlsafe(32) - print(url_for("user.user_callback", provider=provider, _external=True)) query = urlencode( { "client_id": provider_data["client_id"], @@ -42,7 +40,7 @@ def user_authorize(provider): @bp.route("/callback/") def user_callback(provider): if not current_user.is_anonymous: - return redirect(url_for("index")) + return redirect(current_app.config["BASE_URL"]) provider_data = current_app.config["AUTH_PROVIDERS"].get(provider) if not provider_data: @@ -91,9 +89,9 @@ def user_callback(provider): # Login user and map requested data user_data = provider_data["user_info"]["data"](response.json()) - user = User.find_or_create_user(user_data) + user = User.find_or_create_user(user_data, provider) success = login_user(user) if success: user.authenticate_user() - return redirect(url_for("index")) + return redirect(current_app.config["BASE_URL"])