From 657dc4c74d30e7464e94e85fbf6fbf0629111d01 Mon Sep 17 00:00:00 2001 From: pablohashescobar Date: Fri, 12 Dec 2025 14:55:38 +0530 Subject: [PATCH] feat: add sync functionality for OAuth providers - Implemented `check_sync_enabled` method to verify if sync is enabled for Google, GitHub, GitLab, and Gitea. - Added `sync_user_data` method to update user details, including first name, last name, display name, and avatar. - Updated configuration variables to include sync options for each provider. - Integrated sync check into the login/signup process. --- apps/api/plane/authentication/adapter/base.py | 66 ++++++++++++++++++- .../utils/instance_config_variables/core.py | 24 +++++++ 2 files changed, 87 insertions(+), 3 deletions(-) diff --git a/apps/api/plane/authentication/adapter/base.py b/apps/api/plane/authentication/adapter/base.py index d01f3f10b2..868c80370d 100644 --- a/apps/api/plane/authentication/adapter/base.py +++ b/apps/api/plane/authentication/adapter/base.py @@ -90,9 +90,9 @@ class Adapter: """Check if sign up is enabled or not and raise exception if not enabled""" # Get configuration value - (ENABLE_SIGNUP,) = get_configuration_value( - [{"key": "ENABLE_SIGNUP", "default": os.environ.get("ENABLE_SIGNUP", "1")}] - ) + (ENABLE_SIGNUP,) = get_configuration_value([ + {"key": "ENABLE_SIGNUP", "default": os.environ.get("ENABLE_SIGNUP", "1")} + ]) # Check if sign up is disabled and invite is present or not if ENABLE_SIGNUP == "0" and not WorkspaceMemberInvite.objects.filter(email=email).exists(): @@ -108,6 +108,30 @@ class Adapter: def get_avatar_download_headers(self): return {} + def check_sync_enabled(self): + """Check if sync is enabled for the provider""" + if self.provider == "google": + (ENABLE_GOOGLE_SYNC,) = get_configuration_value([ + {"key": "ENABLE_GOOGLE_SYNC", "default": os.environ.get("ENABLE_GOOGLE_SYNC", "0")} + ]) + return ENABLE_GOOGLE_SYNC == "1" + elif self.provider == "github": + (ENABLE_GITHUB_SYNC,) = get_configuration_value([ + {"key": "ENABLE_GITHUB_SYNC", "default": os.environ.get("ENABLE_GITHUB_SYNC", "0")} + ]) + return ENABLE_GITHUB_SYNC == "1" + elif self.provider == "gitlab": + (ENABLE_GITLAB_SYNC,) = get_configuration_value([ + {"key": "ENABLE_GITLAB_SYNC", "default": os.environ.get("ENABLE_GITLAB_SYNC", "0")} + ]) + return ENABLE_GITLAB_SYNC == "1" + elif self.provider == "gitea": + (ENABLE_GITEA_SYNC,) = get_configuration_value([ + {"key": "ENABLE_GITEA_SYNC", "default": os.environ.get("ENABLE_GITEA_SYNC", "0")} + ]) + return ENABLE_GITEA_SYNC == "1" + return False + def download_and_upload_avatar(self, avatar_url, user): """ Downloads avatar from OAuth provider and uploads to our storage. @@ -208,6 +232,38 @@ class Adapter: user.save() return user + def sync_user_data(self, user): + # Update user details + first_name = self.user_data.get("user", {}).get("first_name", "") + last_name = self.user_data.get("user", {}).get("last_name", "") + user.first_name = first_name if first_name else "" + user.last_name = last_name if last_name else "" + + # Get email + email = self.user_data.get("email") + + # Get display name + display_name = self.user_data.get("user", {}).get("display_name") + # If display name is not provided, generate a random display name + if not display_name: + display_name = User.get_display_name(email) + + # Set display name + user.display_name = display_name + + # Download and upload avatar + avatar = self.user_data.get("user", {}).get("avatar", "") + if avatar: + avatar_asset = self.download_and_upload_avatar(avatar_url=avatar, user=user) + if avatar_asset: + user.avatar_asset = avatar_asset + # If avatar upload fails, set the avatar to the original URL + else: + user.avatar = avatar + + user.save() + return user + def complete_login_or_signup(self): # Get email email = self.user_data.get("email") @@ -262,6 +318,10 @@ class Adapter: # Create profile Profile.objects.create(user=user) + # Check if IDP sync is enabled + if self.check_sync_enabled(): + user = self.sync_user_data(user=user) + # Save user data user = self.save_user_data(user=user) diff --git a/apps/api/plane/utils/instance_config_variables/core.py b/apps/api/plane/utils/instance_config_variables/core.py index cf8d8d41fb..4f4833207a 100644 --- a/apps/api/plane/utils/instance_config_variables/core.py +++ b/apps/api/plane/utils/instance_config_variables/core.py @@ -44,6 +44,12 @@ google_config_variables = [ "category": "GOOGLE", "is_encrypted": True, }, + { + "key": "ENABLE_GOOGLE_SYNC", + "value": os.environ.get("ENABLE_GOOGLE_SYNC", "0"), + "category": "GOOGLE", + "is_encrypted": False, + }, ] github_config_variables = [ @@ -65,6 +71,12 @@ github_config_variables = [ "category": "GITHUB", "is_encrypted": False, }, + { + "key": "ENABLE_GITHUB_SYNC", + "value": os.environ.get("ENABLE_GITHUB_SYNC", "0"), + "category": "GITHUB", + "is_encrypted": False, + }, ] @@ -87,6 +99,12 @@ gitlab_config_variables = [ "category": "GITLAB", "is_encrypted": True, }, + { + "key": "ENABLE_GITLAB_SYNC", + "value": os.environ.get("ENABLE_GITLAB_SYNC", "0"), + "category": "GITLAB", + "is_encrypted": False, + }, ] gitea_config_variables = [ @@ -114,6 +132,12 @@ gitea_config_variables = [ "category": "GITEA", "is_encrypted": True, }, + { + "key": "ENABLE_GITEA_SYNC", + "value": os.environ.get("ENABLE_GITEA_SYNC", "0"), + "category": "GITEA", + "is_encrypted": False, + }, ] smtp_config_variables = [