From 43ea577b18bab91f619a4afad55b8ee279ba81b6 Mon Sep 17 00:00:00 2001 From: pablohashescobar Date: Fri, 10 May 2024 11:53:58 +0530 Subject: [PATCH 01/12] dev: update python version --- apiserver/runtime.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apiserver/runtime.txt b/apiserver/runtime.txt index cd0aac54270..8cf46af5fce 100644 --- a/apiserver/runtime.txt +++ b/apiserver/runtime.txt @@ -1 +1 @@ -python-3.11.9 \ No newline at end of file +python-3.12.3 \ No newline at end of file From d0ccd8cab4309178716d4c87cb8ff86f76b45bd2 Mon Sep 17 00:00:00 2001 From: pablohashescobar Date: Fri, 10 May 2024 12:51:50 +0530 Subject: [PATCH 02/12] dev: handle magic code attempt exhausted --- .../plane/authentication/adapter/error.py | 75 ++++++++++--------- .../provider/credentials/magic_code.py | 8 +- apiserver/plane/settings/production.py | 2 - 3 files changed, 45 insertions(+), 40 deletions(-) diff --git a/apiserver/plane/authentication/adapter/error.py b/apiserver/plane/authentication/adapter/error.py index 4b975939d58..73809b9ad5c 100644 --- a/apiserver/plane/authentication/adapter/error.py +++ b/apiserver/plane/authentication/adapter/error.py @@ -1,51 +1,52 @@ AUTHENTICATION_ERROR_CODES = { # Global "INSTANCE_NOT_CONFIGURED": 5000, - "INVALID_EMAIL": 5012, - "EMAIL_REQUIRED": 5013, - "SIGNUP_DISABLED": 5001, + "INVALID_EMAIL": 5005, + "EMAIL_REQUIRED": 5010, + "SIGNUP_DISABLED": 5015, # Password strength - "INVALID_PASSWORD": 5002, - "SMTP_NOT_CONFIGURED": 5007, + "INVALID_PASSWORD": 5020, + "SMTP_NOT_CONFIGURED": 5025, # Sign Up - "USER_ALREADY_EXIST": 5003, - "AUTHENTICATION_FAILED_SIGN_UP": 5006, - "REQUIRED_EMAIL_PASSWORD_SIGN_UP": 5015, - "INVALID_EMAIL_SIGN_UP": 5017, - "INVALID_EMAIL_MAGIC_SIGN_UP": 5019, - "MAGIC_SIGN_UP_EMAIL_CODE_REQUIRED": 5023, + "USER_ALREADY_EXIST": 5030, + "AUTHENTICATION_FAILED_SIGN_UP": 5035, + "REQUIRED_EMAIL_PASSWORD_SIGN_UP": 5040, + "INVALID_EMAIL_SIGN_UP": 5045, + "INVALID_EMAIL_MAGIC_SIGN_UP": 5050, + "MAGIC_SIGN_UP_EMAIL_CODE_REQUIRED": 5055, # Sign In - "USER_DOES_NOT_EXIST": 5004, - "AUTHENTICATION_FAILED_SIGN_IN": 5005, - "REQUIRED_EMAIL_PASSWORD_SIGN_IN": 5014, - "INVALID_EMAIL_SIGN_IN": 5016, - "INVALID_EMAIL_MAGIC_SIGN_IN": 5018, - "MAGIC_SIGN_IN_EMAIL_CODE_REQUIRED": 5022, - # Both Sign in and Sign up - "INVALID_MAGIC_CODE": 5008, - "EXPIRED_MAGIC_CODE": 5009, + "USER_DOES_NOT_EXIST": 5060, + "AUTHENTICATION_FAILED_SIGN_IN": 5065, + "REQUIRED_EMAIL_PASSWORD_SIGN_IN": 5070, + "INVALID_EMAIL_SIGN_IN": 5075, + "INVALID_EMAIL_MAGIC_SIGN_IN": 5080, + "MAGIC_SIGN_IN_EMAIL_CODE_REQUIRED": 5085, + # Both Sign in and Sign up for magic + "INVALID_MAGIC_CODE": 5090, + "EXPIRED_MAGIC_CODE": 5095, + "EMAIL_CODE_ATTEMPT_EXHAUSTED": 5100, # Oauth - "GOOGLE_NOT_CONFIGURED": 5010, - "GITHUB_NOT_CONFIGURED": 5011, - "GOOGLE_OAUTH_PROVIDER_ERROR": 5021, - "GITHUB_OAUTH_PROVIDER_ERROR": 5020, + "GOOGLE_NOT_CONFIGURED": 5105, + "GITHUB_NOT_CONFIGURED": 5110, + "GOOGLE_OAUTH_PROVIDER_ERROR": 5115, + "GITHUB_OAUTH_PROVIDER_ERROR": 5120, # Reset Password - "INVALID_PASSWORD_TOKEN": 5024, - "EXPIRED_PASSWORD_TOKEN": 5025, + "INVALID_PASSWORD_TOKEN": 5125, + "EXPIRED_PASSWORD_TOKEN": 5130, # Change password - "INCORRECT_OLD_PASSWORD": 5026, - "INVALID_NEW_PASSWORD": 5027, + "INCORRECT_OLD_PASSWORD": 5135, + "INVALID_NEW_PASSWORD": 5140, # set passowrd - "PASSWORD_ALREADY_SET": 5028, + "PASSWORD_ALREADY_SET": 5145, # Admin - "ADMIN_ALREADY_EXIST": 5029, - "REQUIRED_ADMIN_EMAIL_PASSWORD_FIRST_NAME": 5030, - "INVALID_ADMIN_EMAIL": 5031, - "INVALID_ADMIN_PASSWORD": 5032, - "REQUIRED_ADMIN_EMAIL_PASSWORD": 5033, - "ADMIN_AUTHENTICATION_FAILED": 5034, - "ADMIN_USER_ALREADY_EXIST": 5035, - "ADMIN_USER_DOES_NOT_EXIST": 5036, + "ADMIN_ALREADY_EXIST": 5150, + "REQUIRED_ADMIN_EMAIL_PASSWORD_FIRST_NAME": 5155, + "INVALID_ADMIN_EMAIL": 5160, + "INVALID_ADMIN_PASSWORD": 5165, + "REQUIRED_ADMIN_EMAIL_PASSWORD": 5170, + "ADMIN_AUTHENTICATION_FAILED": 5175, + "ADMIN_USER_ALREADY_EXIST": 5180, + "ADMIN_USER_DOES_NOT_EXIST": 5185, } diff --git a/apiserver/plane/authentication/provider/credentials/magic_code.py b/apiserver/plane/authentication/provider/credentials/magic_code.py index 71451ef0d65..c1207d14d50 100644 --- a/apiserver/plane/authentication/provider/credentials/magic_code.py +++ b/apiserver/plane/authentication/provider/credentials/magic_code.py @@ -77,7 +77,13 @@ def initiate(self): current_attempt = data["current_attempt"] + 1 if data["current_attempt"] > 2: - return key, "" + raise AuthenticationException( + error_code=AUTHENTICATION_ERROR_CODES[ + "EMAIL_CODE_ATTEMPT_EXHAUSTED" + ], + error_message="EMAIL_CODE_ATTEMPT_EXHAUSTED", + payload={"email": self.key}, + ) value = { "current_attempt": current_attempt, diff --git a/apiserver/plane/settings/production.py b/apiserver/plane/settings/production.py index c56222c67e1..806f83aca7e 100644 --- a/apiserver/plane/settings/production.py +++ b/apiserver/plane/settings/production.py @@ -12,8 +12,6 @@ INSTALLED_APPS += ("scout_apm.django",) # noqa -# Honor the 'X-Forwarded-Proto' header for request.is_secure() -SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https") # Scout Settings SCOUT_MONITOR = os.environ.get("SCOUT_MONITOR", False) From bf33f1bf386b5053a15032f7085a65c2194deaa9 Mon Sep 17 00:00:00 2001 From: pablohashescobar Date: Fri, 10 May 2024 13:39:00 +0530 Subject: [PATCH 03/12] dev: update app, space and god mode redirection paths --- .../plane/authentication/views/app/email.py | 10 +++--- .../plane/authentication/views/app/magic.py | 6 ++-- .../views/app/password_management.py | 5 +-- .../plane/authentication/views/app/signout.py | 6 ++-- .../plane/authentication/views/space/email.py | 24 +++++++------- .../authentication/views/space/github.py | 2 +- .../plane/authentication/views/space/magic.py | 14 ++++---- .../views/space/password_management.py | 6 ++-- .../authentication/views/space/signout.py | 8 ++--- apiserver/plane/license/api/views/admin.py | 32 ++++++++----------- 10 files changed, 52 insertions(+), 61 deletions(-) diff --git a/apiserver/plane/authentication/views/app/email.py b/apiserver/plane/authentication/views/app/email.py index 7ef6ac9f4ca..14d2c64d03c 100644 --- a/apiserver/plane/authentication/views/app/email.py +++ b/apiserver/plane/authentication/views/app/email.py @@ -43,7 +43,7 @@ def post(self, request): # Base URL join url = urljoin( base_host(request=request), - "accounts/sign-in?" + urlencode(params), + "sign-in?" + urlencode(params), ) return HttpResponseRedirect(url) @@ -67,7 +67,7 @@ def post(self, request): params["next_path"] = str(next_path) url = urljoin( base_host(request=request), - "accounts/sign-in?" + urlencode(params), + "sign-in?" + urlencode(params), ) return HttpResponseRedirect(url) @@ -86,7 +86,7 @@ def post(self, request): params["next_path"] = str(next_path) url = urljoin( base_host(request=request), - "accounts/sign-in?" + urlencode(params), + "sign-in?" + urlencode(params), ) return HttpResponseRedirect(url) @@ -101,7 +101,7 @@ def post(self, request): params["next_path"] = str(next_path) url = urljoin( base_host(request=request), - "accounts/sign-in?" + urlencode(params), + "sign-in?" + urlencode(params), ) return HttpResponseRedirect(url) @@ -129,7 +129,7 @@ def post(self, request): params["next_path"] = str(next_path) url = urljoin( base_host(request=request), - "accounts/sign-in?" + urlencode(params), + "sign-in?" + urlencode(params), ) return HttpResponseRedirect(url) diff --git a/apiserver/plane/authentication/views/app/magic.py b/apiserver/plane/authentication/views/app/magic.py index 8f9f3633b43..9050f051c53 100644 --- a/apiserver/plane/authentication/views/app/magic.py +++ b/apiserver/plane/authentication/views/app/magic.py @@ -91,7 +91,7 @@ def post(self, request): params["next_path"] = str(next_path) url = urljoin( base_host(request=request), - "accounts/sign-in?" + urlencode(params), + "sign-in?" + urlencode(params), ) return HttpResponseRedirect(url) @@ -105,7 +105,7 @@ def post(self, request): params["next_path"] = str(next_path) url = urljoin( base_host(request=request), - "accounts/sign-in?" + urlencode(params), + "sign-in?" + urlencode(params), ) return HttpResponseRedirect(url) @@ -138,7 +138,7 @@ def post(self, request): params["next_path"] = str(next_path) url = urljoin( base_host(request=request), - "accounts/sign-in?" + urlencode(params), + "sign-in?" + urlencode(params), ) return HttpResponseRedirect(url) diff --git a/apiserver/plane/authentication/views/app/password_management.py b/apiserver/plane/authentication/views/app/password_management.py index 80803cd253c..152605cc05a 100644 --- a/apiserver/plane/authentication/views/app/password_management.py +++ b/apiserver/plane/authentication/views/app/password_management.py @@ -160,7 +160,8 @@ def post(self, request, uidb64, token): ) url = urljoin( base_host(request=request), - "?" + urlencode(exc.get_error_dict()), + "accounts/reset-password?" + + urlencode(exc.get_error_dict()), ) return HttpResponseRedirect(url) @@ -185,7 +186,7 @@ def post(self, request, uidb64, token): url = urljoin( base_host(request=request), - "accounts/sign-in?" + urlencode({"success": True}), + "sign-in?" + urlencode({"success": True}), ) return HttpResponseRedirect(url) except DjangoUnicodeDecodeError: diff --git a/apiserver/plane/authentication/views/app/signout.py b/apiserver/plane/authentication/views/app/signout.py index 967f398eb10..b8d36dd1a28 100644 --- a/apiserver/plane/authentication/views/app/signout.py +++ b/apiserver/plane/authentication/views/app/signout.py @@ -25,10 +25,8 @@ def post(self, request): logout(request) url = urljoin( base_host(request=request), - "accounts/sign-in?" + urlencode({"success": "true"}), + "sign-in?" + urlencode({"success": "true"}), ) return HttpResponseRedirect(url) except Exception: - return HttpResponseRedirect( - base_host(request=request), "accounts/sign-in" - ) + return HttpResponseRedirect(base_host(request=request), "sign-in") diff --git a/apiserver/plane/authentication/views/space/email.py b/apiserver/plane/authentication/views/space/email.py index 4505332ebe6..9270fd1ea6f 100644 --- a/apiserver/plane/authentication/views/space/email.py +++ b/apiserver/plane/authentication/views/space/email.py @@ -38,7 +38,7 @@ def post(self, request): params["next_path"] = str(next_path) url = urljoin( base_host(request=request, is_space=True), - "accounts/sign-in?" + urlencode(params), + "?" + urlencode(params), ) return HttpResponseRedirect(url) @@ -60,7 +60,7 @@ def post(self, request): params["next_path"] = str(next_path) url = urljoin( base_host(request=request, is_space=True), - "spaces/accounts/sign-in?" + urlencode(params), + "?" + urlencode(params), ) return HttpResponseRedirect(url) @@ -79,7 +79,7 @@ def post(self, request): params["next_path"] = str(next_path) url = urljoin( base_host(request=request, is_space=True), - "spaces/accounts/sign-in?" + urlencode(params), + "?" + urlencode(params), ) return HttpResponseRedirect(url) @@ -94,7 +94,7 @@ def post(self, request): params["next_path"] = str(next_path) url = urljoin( base_host(request=request, is_space=True), - "spaces/accounts/sign-in?" + urlencode(params), + "?" + urlencode(params), ) return HttpResponseRedirect(url) @@ -108,7 +108,7 @@ def post(self, request): # redirect to next path url = urljoin( base_host(request=request, is_space=True), - str(next_path) if next_path else "/", + str(next_path) if next_path else "", ) return HttpResponseRedirect(url) except AuthenticationException as e: @@ -117,7 +117,7 @@ def post(self, request): params["next_path"] = str(next_path) url = urljoin( base_host(request=request, is_space=True), - "spaces/accounts/sign-in?" + urlencode(params), + "?" + urlencode(params), ) return HttpResponseRedirect(url) @@ -141,7 +141,7 @@ def post(self, request): params["next_path"] = str(next_path) url = urljoin( base_host(request=request, is_space=True), - "spaces?" + urlencode(params), + "?" + urlencode(params), ) return HttpResponseRedirect(url) @@ -162,7 +162,7 @@ def post(self, request): params["next_path"] = str(next_path) url = urljoin( base_host(request=request, is_space=True), - "spaces?" + urlencode(params), + "?" + urlencode(params), ) return HttpResponseRedirect(url) # Validate the email @@ -181,7 +181,7 @@ def post(self, request): params["next_path"] = str(next_path) url = urljoin( base_host(request=request, is_space=True), - "spaces?" + urlencode(params), + "?" + urlencode(params), ) return HttpResponseRedirect(url) @@ -196,7 +196,7 @@ def post(self, request): params["next_path"] = str(next_path) url = urljoin( base_host(request=request, is_space=True), - "spaces?" + urlencode(params), + "?" + urlencode(params), ) return HttpResponseRedirect(url) @@ -210,7 +210,7 @@ def post(self, request): # redirect to referer path url = urljoin( base_host(request=request, is_space=True), - str(next_path) if next_path else "spaces", + str(next_path) if next_path else "", ) return HttpResponseRedirect(url) except AuthenticationException as e: @@ -219,6 +219,6 @@ def post(self, request): params["next_path"] = str(next_path) url = urljoin( base_host(request=request, is_space=True), - "spaces?" + urlencode(params), + "?" + urlencode(params), ) return HttpResponseRedirect(url) diff --git a/apiserver/plane/authentication/views/space/github.py b/apiserver/plane/authentication/views/space/github.py index 4a0f2309847..58c1f5f908e 100644 --- a/apiserver/plane/authentication/views/space/github.py +++ b/apiserver/plane/authentication/views/space/github.py @@ -111,7 +111,7 @@ def get(self, request): user_login(request=request, user=user) # Process workspace and project invitations # redirect to referer path - url = urljoin(base_host, str(next_path) if next_path else "/") + url = urljoin(base_host, str(next_path) if next_path else "") return HttpResponseRedirect(url) except AuthenticationException as e: params = e.get_error_dict() diff --git a/apiserver/plane/authentication/views/space/magic.py b/apiserver/plane/authentication/views/space/magic.py index 52771f71b99..fc1281c4bf1 100644 --- a/apiserver/plane/authentication/views/space/magic.py +++ b/apiserver/plane/authentication/views/space/magic.py @@ -86,7 +86,7 @@ def post(self, request): params["next_path"] = str(next_path) url = urljoin( base_host(request=request, is_space=True), - "spaces/accounts/sign-in?" + urlencode(params), + "?" + urlencode(params), ) return HttpResponseRedirect(url) @@ -99,7 +99,7 @@ def post(self, request): params["next_path"] = str(next_path) url = urljoin( base_host(request=request, is_space=True), - "accounts/sign-in?" + urlencode(params), + "?" + urlencode(params), ) return HttpResponseRedirect(url) @@ -113,10 +113,10 @@ def post(self, request): # redirect to referer path profile = Profile.objects.get(user=user) if user.is_password_autoset and profile.is_onboarded: - path = "spaces/accounts/set-password" + path = "accounts/set-password" else: # Get the redirection path - path = str(next_path) if next_path else "spaces" + path = str(next_path) if next_path else "" url = urljoin(base_host(request=request, is_space=True), path) return HttpResponseRedirect(url) @@ -126,7 +126,7 @@ def post(self, request): params["next_path"] = str(next_path) url = urljoin( base_host(request=request, is_space=True), - "spaces/accounts/sign-in?" + urlencode(params), + "?" + urlencode(params), ) return HttpResponseRedirect(url) @@ -152,7 +152,7 @@ def post(self, request): params["next_path"] = str(next_path) url = urljoin( base_host(request=request, is_space=True), - "spaces/accounts/sign-in?" + urlencode(params), + "?" + urlencode(params), ) return HttpResponseRedirect(url) @@ -190,6 +190,6 @@ def post(self, request): params["next_path"] = str(next_path) url = urljoin( base_host(request=request, is_space=True), - "spaces/accounts/sign-in?" + urlencode(params), + "?" + urlencode(params), ) return HttpResponseRedirect(url) diff --git a/apiserver/plane/authentication/views/space/password_management.py b/apiserver/plane/authentication/views/space/password_management.py index aeac9776d1e..5263c89566d 100644 --- a/apiserver/plane/authentication/views/space/password_management.py +++ b/apiserver/plane/authentication/views/space/password_management.py @@ -183,11 +183,9 @@ def post(self, request, uidb64, token): user.is_password_autoset = False user.save() - url = urljoin( - base_host(request=request, is_space=True), - "accounts/sign-in?" + urlencode({"success": True}), + return HttpResponseRedirect( + base_host(request=request, is_space=True) ) - return HttpResponseRedirect(url) except DjangoUnicodeDecodeError: exc = AuthenticationException( error_code=AUTHENTICATION_ERROR_CODES[ diff --git a/apiserver/plane/authentication/views/space/signout.py b/apiserver/plane/authentication/views/space/signout.py index 3cfd6d47114..655d8b1c8cc 100644 --- a/apiserver/plane/authentication/views/space/signout.py +++ b/apiserver/plane/authentication/views/space/signout.py @@ -23,12 +23,10 @@ def post(self, request): user.save() # Log the user out logout(request) - url = urljoin( - base_host(request=request, is_space=True), - "accounts/sign-in?" + urlencode({"success": "true"}), + return HttpResponseRedirect( + base_host(request=request, is_space=True) ) - return HttpResponseRedirect(url) except Exception: return HttpResponseRedirect( - base_host(request=request, is_space=True), "accounts/sign-in" + base_host(request=request, is_space=True) ) diff --git a/apiserver/plane/license/api/views/admin.py b/apiserver/plane/license/api/views/admin.py index ed3c00f17a4..490d0d2ca64 100644 --- a/apiserver/plane/license/api/views/admin.py +++ b/apiserver/plane/license/api/views/admin.py @@ -107,7 +107,7 @@ def post(self, request): ) url = urljoin( base_host(request=request, is_admin=True), - "god-mode/setup?" + urlencode(exc.get_error_dict()), + "setup?" + urlencode(exc.get_error_dict()), ) return HttpResponseRedirect(url) @@ -119,7 +119,7 @@ def post(self, request): ) url = urljoin( base_host(request=request, is_admin=True), - "god-mode/setup?" + urlencode(exc.get_error_dict()), + "setup?" + urlencode(exc.get_error_dict()), ) return HttpResponseRedirect(url) @@ -148,7 +148,7 @@ def post(self, request): ) url = urljoin( base_host(request=request, is_admin=True), - "god-mode/setup?" + urlencode(exc.get_error_dict()), + "setup?" + urlencode(exc.get_error_dict()), ) return HttpResponseRedirect(url) @@ -170,7 +170,7 @@ def post(self, request): ) url = urljoin( base_host(request=request, is_admin=True), - "god-mode/setup?" + urlencode(exc.get_error_dict()), + "setup?" + urlencode(exc.get_error_dict()), ) return HttpResponseRedirect(url) @@ -192,7 +192,7 @@ def post(self, request): ) url = urljoin( base_host(request=request, is_admin=True), - "god-mode/setup?" + urlencode(exc.get_error_dict()), + "setup?" + urlencode(exc.get_error_dict()), ) return HttpResponseRedirect(url) else: @@ -214,7 +214,7 @@ def post(self, request): ) url = urljoin( base_host(request=request, is_admin=True), - "god-mode/setup?" + urlencode(exc.get_error_dict()), + "setup?" + urlencode(exc.get_error_dict()), ) return HttpResponseRedirect(url) @@ -248,9 +248,7 @@ def post(self, request): # get tokens for user user_login(request=request, user=user) - url = urljoin( - base_host(request=request, is_admin=True), "god-mode/general" - ) + url = urljoin(base_host(request=request, is_admin=True), "general") return HttpResponseRedirect(url) @@ -272,7 +270,7 @@ def post(self, request): ) url = urljoin( base_host(request=request, is_admin=True), - "god-mode/login?" + urlencode(exc.get_error_dict()), + "?" + urlencode(exc.get_error_dict()), ) return HttpResponseRedirect(url) @@ -293,7 +291,7 @@ def post(self, request): ) url = urljoin( base_host(request=request, is_admin=True), - "god-mode/login?" + urlencode(exc.get_error_dict()), + "?" + urlencode(exc.get_error_dict()), ) return HttpResponseRedirect(url) @@ -311,7 +309,7 @@ def post(self, request): ) url = urljoin( base_host(request=request, is_admin=True), - "god-mode/login?" + urlencode(exc.get_error_dict()), + "?" + urlencode(exc.get_error_dict()), ) return HttpResponseRedirect(url) @@ -331,7 +329,7 @@ def post(self, request): ) url = urljoin( base_host(request=request, is_admin=True), - "god-mode/login?" + urlencode(exc.get_error_dict()), + "?" + urlencode(exc.get_error_dict()), ) return HttpResponseRedirect(url) @@ -348,7 +346,7 @@ def post(self, request): ) url = urljoin( base_host(request=request, is_admin=True), - "god-mode/login?" + urlencode(exc.get_error_dict()), + "?" + urlencode(exc.get_error_dict()), ) return HttpResponseRedirect(url) @@ -365,7 +363,7 @@ def post(self, request): ) url = urljoin( base_host(request=request, is_admin=True), - "god-mode/login?" + urlencode(exc.get_error_dict()), + "?" + urlencode(exc.get_error_dict()), ) return HttpResponseRedirect(url) # settings last active for the user @@ -379,9 +377,7 @@ def post(self, request): # get tokens for user user_login(request=request, user=user) - url = urljoin( - base_host(request=request, is_admin=True), "god-mode/general" - ) + url = urljoin(base_host(request=request, is_admin=True), "general") return HttpResponseRedirect(url) From 84eedf5a2a3dcc1f8d93ca74579e1636f094305e Mon Sep 17 00:00:00 2001 From: guru_sainath Date: Fri, 10 May 2024 13:56:53 +0530 Subject: [PATCH 04/12] fix: handled signup and signin workflow --- .../account/auth-forms/auth-root.tsx | 72 ++++---- web/components/account/auth-forms/email.tsx | 20 ++- .../account/auth-forms/password.tsx | 47 ++--- .../account/auth-forms/unique-code.tsx | 114 +++++------- .../account/password-strength-meter.tsx | 4 +- web/helpers/authentication.helper.tsx | 168 ++++++++++++------ web/lib/wrappers/authentication-wrapper.tsx | 6 +- web/pages/accounts/forgot-password.tsx | 2 +- web/pages/index.tsx | 2 +- web/pages/{accounts => }/sign-in.tsx | 0 10 files changed, 244 insertions(+), 191 deletions(-) rename web/pages/{accounts => }/sign-in.tsx (100%) diff --git a/web/components/account/auth-forms/auth-root.tsx b/web/components/account/auth-forms/auth-root.tsx index 1494f91f132..4c479af2883 100644 --- a/web/components/account/auth-forms/auth-root.tsx +++ b/web/components/account/auth-forms/auth-root.tsx @@ -2,7 +2,6 @@ import React, { FC, useEffect, useState } from "react"; import { observer } from "mobx-react"; import { useRouter } from "next/router"; import { IEmailCheckData } from "@plane/types"; -import { TOAST_TYPE, setToast } from "@plane/ui"; // components import { AuthHeader, @@ -43,6 +42,7 @@ export const AuthRoot: FC = observer((props) => { const [authStep, setAuthStep] = useState(EAuthSteps.EMAIL); const [email, setEmail] = useState(emailParam ? emailParam.toString() : ""); const [errorInfo, setErrorInfo] = useState(undefined); + const [isPasswordAutoset, setIsPasswordAutoset] = useState(true); // hooks const { instance } = useInstance(); @@ -63,52 +63,57 @@ export const AuthRoot: FC = observer((props) => { ) ) setAuthStep(EAuthSteps.UNIQUE_CODE); - - // validating weather to show alert to banner - if (errorhandler?.type === EErrorAlertType.TOAST_ALERT) { - setToast({ - type: TOAST_TYPE.ERROR, - title: errorhandler?.title, - message: errorhandler?.message as string, - }); - } else setErrorInfo(errorhandler); + setErrorInfo(errorhandler); } } }, [error_code, authMode]); - // step 1 submit handler- email verification + // submit handler- email verification const handleEmailVerification = async (data: IEmailCheckData) => { setEmail(data.email); - const emailCheckRequest = authMode === EAuthModes.SIGN_IN ? authService.signInEmailCheck(data) : authService.signUpEmailCheck(data); await emailCheckRequest - .then((response) => { + .then(async (response) => { if (authMode === EAuthModes.SIGN_IN) { - if (response.is_password_autoset) setAuthStep(EAuthSteps.UNIQUE_CODE); - else setAuthStep(EAuthSteps.PASSWORD); + if (response.is_password_autoset) { + setAuthStep(EAuthSteps.UNIQUE_CODE); + generateEmailUniqueCode(data.email); + } else { + setIsPasswordAutoset(false); + setAuthStep(EAuthSteps.PASSWORD); + } } else { - if (instance && instance?.config?.is_smtp_configured) setAuthStep(EAuthSteps.UNIQUE_CODE); - else setAuthStep(EAuthSteps.PASSWORD); + if (instance && instance?.config?.is_smtp_configured) { + setAuthStep(EAuthSteps.UNIQUE_CODE); + generateEmailUniqueCode(data.email); + } else setAuthStep(EAuthSteps.PASSWORD); } }) .catch((error) => { const errorhandler = authErrorHandler(error?.error_code.toString(), data?.email || undefined); - if (errorhandler?.type === EErrorAlertType.BANNER_ALERT) { - setErrorInfo(errorhandler); - return; - } else if (errorhandler?.type === EErrorAlertType.TOAST_ALERT) - setToast({ - type: TOAST_TYPE.ERROR, - title: errorhandler?.title, - message: (errorhandler?.message as string) || "Something went wrong. Please try again.", - }); + if (errorhandler?.type) setErrorInfo(errorhandler); + }); + }; + + // generating the unique code + const generateEmailUniqueCode = async (email: string): Promise<{ code: string } | undefined> => { + const payload = { email: email }; + return await authService + .generateUniqueCode(payload) + .then(() => ({ code: "" })) + .catch((error) => { + const errorhandler = authErrorHandler(error?.error_code.toString()); + if (errorhandler?.type) setErrorInfo(errorhandler); + throw error; }); }; const isOAuthEnabled = - instance?.config && (instance?.config?.is_google_enabled || instance?.config?.is_github_enabled); + (instance?.config && (instance?.config?.is_google_enabled || instance?.config?.is_github_enabled)) || false; + + const isSMTPConfigured = (instance?.config && instance?.config?.is_smtp_configured) || false; return (
@@ -125,24 +130,29 @@ export const AuthRoot: FC = observer((props) => { {authStep === EAuthSteps.EMAIL && } {authStep === EAuthSteps.UNIQUE_CODE && ( { setEmail(""); setAuthStep(EAuthSteps.EMAIL); }} - submitButtonText="Continue" - mode={authMode} + generateEmailUniqueCode={generateEmailUniqueCode} /> )} {authStep === EAuthSteps.PASSWORD && ( { setEmail(""); setAuthStep(EAuthSteps.EMAIL); }} - handleStepChange={(step) => setAuthStep(step)} - mode={authMode} + handleAuthStep={(step: EAuthSteps) => { + if (step === EAuthSteps.UNIQUE_CODE) generateEmailUniqueCode(email); + setAuthStep(step); + }} /> )} {isOAuthEnabled && } diff --git a/web/components/account/auth-forms/email.tsx b/web/components/account/auth-forms/email.tsx index 573dc59e676..df20d98ff71 100644 --- a/web/components/account/auth-forms/email.tsx +++ b/web/components/account/auth-forms/email.tsx @@ -7,6 +7,7 @@ import { IEmailCheckData } from "@plane/types"; // ui import { Button, Input, Spinner } from "@plane/ui"; // helpers +import { cn } from "@/helpers/common.helper"; import { checkEmailValidity } from "@/helpers/string.helper"; type TAuthEmailForm = { @@ -38,28 +39,31 @@ export const AuthEmailForm: FC = observer((props) => { const isButtonDisabled = email.length === 0 || Boolean(emailError?.email) || isSubmitting; return ( -
+
-
+
setEmail(e.target.value)} - hasError={Boolean(emailError?.email)} placeholder="name@company.com" - className="h-[46px] w-full border border-onboarding-border-100 pr-12 placeholder:text-onboarding-text-400" + className={`h-[46px] w-full placeholder:text-onboarding-text-400 border-0`} autoFocus /> {email.length > 0 && ( - setEmail("")} - /> +
+ setEmail("")} /> +
)}
{emailError?.email && ( diff --git a/web/components/account/auth-forms/password.tsx b/web/components/account/auth-forms/password.tsx index 37c6d6506a7..be9e32c8a73 100644 --- a/web/components/account/auth-forms/password.tsx +++ b/web/components/account/auth-forms/password.tsx @@ -14,15 +14,17 @@ import { EAuthModes, EAuthSteps } from "@/helpers/authentication.helper"; import { API_BASE_URL } from "@/helpers/common.helper"; import { getPasswordStrength } from "@/helpers/password.helper"; // hooks -import { useEventTracker, useInstance } from "@/hooks/store"; +import { useEventTracker } from "@/hooks/store"; // services import { AuthService } from "@/services/auth.service"; type Props = { email: string; + isPasswordAutoset: boolean; + isSMTPConfigured: boolean; mode: EAuthModes; - handleStepChange: (step: EAuthSteps) => void; handleEmailClear: () => void; + handleAuthStep: (step: EAuthSteps) => void; }; type TPasswordFormValues = { @@ -39,9 +41,8 @@ const defaultValues: TPasswordFormValues = { const authService = new AuthService(); export const AuthPasswordForm: React.FC = observer((props: Props) => { - const { email, handleStepChange, handleEmailClear, mode } = props; + const { email, isSMTPConfigured, handleAuthStep, handleEmailClear, mode } = props; // hooks - const { instance } = useInstance(); const { captureEvent } = useEventTracker(); // states const [csrfToken, setCsrfToken] = useState(undefined); @@ -56,9 +57,6 @@ export const AuthPasswordForm: React.FC = observer((props: Props) => { const handleShowPassword = (key: keyof typeof showPassword) => setShowPassword((prev) => ({ ...prev, [key]: !prev[key] })); - // derived values - const isSmtpConfigured = instance?.config?.is_smtp_configured; - const handleFormChange = (key: keyof TPasswordFormValues, value: string) => setPasswordFormData((prev) => ({ ...prev, [key]: value })); @@ -68,13 +66,13 @@ export const AuthPasswordForm: React.FC = observer((props: Props) => { }, [csrfToken]); const redirectToUniqueCodeSignIn = async () => { - handleStepChange(EAuthSteps.UNIQUE_CODE); + handleAuthStep(EAuthSteps.UNIQUE_CODE); }; const passwordSupport = mode === EAuthModes.SIGN_IN ? ( -
- {isSmtpConfigured ? ( +
+ {isSMTPConfigured ? ( captureEvent(FORGOT_PASSWORD)} href={`/accounts/forgot-password?email=${email}`} @@ -87,7 +85,10 @@ export const AuthPasswordForm: React.FC = observer((props: Props) => { )}
) : ( - isPasswordInputFocused && + passwordFormData.password.length > 0 && + (getPasswordStrength(passwordFormData.password) < 3 || isPasswordInputFocused) && ( + + ) ); const isButtonDisabled = useMemo( @@ -112,11 +113,14 @@ export const AuthPasswordForm: React.FC = observer((props: Props) => { onError={() => setIsSubmitting(false)} > +
-
+ {mode === EAuthModes.SIGN_UP && (
)} +
{mode === EAuthModes.SIGN_IN ? ( <> - {instance && isSmtpConfigured && ( + {isSMTPConfigured && (
- + +
+ +
); }; diff --git a/web/components/account/password-strength-meter.tsx b/web/components/account/password-strength-meter.tsx index 86ee814c895..ebfdad7bb31 100644 --- a/web/components/account/password-strength-meter.tsx +++ b/web/components/account/password-strength-meter.tsx @@ -24,9 +24,9 @@ export const PasswordStrengthMeter: React.FC = (props: Props) => { text = "Password is too short"; textColor = `text-[#DC3E42]`; } else if (strength < 3) { - bars = [`bg-[#FFBA18]`, `bg-[#FFBA18]`, `bg-[#F0F0F3]`]; + bars = [`bg-[#DC3E42]`, `bg-[#F0F0F3]`, `bg-[#F0F0F3]`]; text = "Password is weak"; - textColor = `text-[#FFBA18]`; + textColor = `text-[#F0F0F3]`; } else { bars = [`bg-[#3E9B4F]`, `bg-[#3E9B4F]`, `bg-[#3E9B4F]`]; text = "Password is strong"; diff --git a/web/helpers/authentication.helper.tsx b/web/helpers/authentication.helper.tsx index 1c8c9ad7456..88a40dd579b 100644 --- a/web/helpers/authentication.helper.tsx +++ b/web/helpers/authentication.helper.tsx @@ -22,7 +22,6 @@ export enum EAuthSteps { export enum EErrorAlertType { BANNER_ALERT = "BANNER_ALERT", - TOAST_ALERT = "TOAST_ALERT", INLINE_FIRST_NAME = "INLINE_FIRST_NAME", INLINE_EMAIL = "INLINE_EMAIL", INLINE_PASSWORD = "INLINE_PASSWORD", @@ -32,42 +31,52 @@ export enum EErrorAlertType { export enum EAuthenticationErrorCodes { // Global INSTANCE_NOT_CONFIGURED = "5000", - SIGNUP_DISABLED = "5001", - INVALID_PASSWORD = "5002", // Password strength validation - SMTP_NOT_CONFIGURED = "5007", - // email check - INVALID_EMAIL = "5012", - EMAIL_REQUIRED = "5013", + INVALID_EMAIL = "5005", + EMAIL_REQUIRED = "5010", + SIGNUP_DISABLED = "5015", + // Password strength + INVALID_PASSWORD = "5020", + SMTP_NOT_CONFIGURED = "5025", // Sign Up - USER_ALREADY_EXIST = "5003", - REQUIRED_EMAIL_PASSWORD_SIGN_UP = "5015", - AUTHENTICATION_FAILED_SIGN_UP = "5006", - INVALID_EMAIL_SIGN_UP = "5017", - MAGIC_SIGN_UP_EMAIL_CODE_REQUIRED = "5023", - INVALID_EMAIL_MAGIC_SIGN_UP = "5019", + USER_ALREADY_EXIST = "5030", + AUTHENTICATION_FAILED_SIGN_UP = "5035", + REQUIRED_EMAIL_PASSWORD_SIGN_UP = "5040", + INVALID_EMAIL_SIGN_UP = "5045", + INVALID_EMAIL_MAGIC_SIGN_UP = "5050", + MAGIC_SIGN_UP_EMAIL_CODE_REQUIRED = "5055", // Sign In - USER_DOES_NOT_EXIST = "5004", - REQUIRED_EMAIL_PASSWORD_SIGN_IN = "5014", - AUTHENTICATION_FAILED_SIGN_IN = "5005", - INVALID_EMAIL_SIGN_IN = "5016", - MAGIC_SIGN_IN_EMAIL_CODE_REQUIRED = "5022", - INVALID_EMAIL_MAGIC_SIGN_IN = "5018", - // Both Sign in and Sign up - INVALID_MAGIC_CODE = "5008", - EXPIRED_MAGIC_CODE = "5009", + USER_DOES_NOT_EXIST = "5060", + AUTHENTICATION_FAILED_SIGN_IN = "5065", + REQUIRED_EMAIL_PASSWORD_SIGN_IN = "5070", + INVALID_EMAIL_SIGN_IN = "5075", + INVALID_EMAIL_MAGIC_SIGN_IN = "5080", + MAGIC_SIGN_IN_EMAIL_CODE_REQUIRED = "5085", + // Both Sign in and Sign up for magic + INVALID_MAGIC_CODE = "5090", + EXPIRED_MAGIC_CODE = "5095", + EMAIL_CODE_ATTEMPT_EXHAUSTED = "5100", // Oauth - GOOGLE_NOT_CONFIGURED = "5010", - GITHUB_NOT_CONFIGURED = "5011", - GOOGLE_OAUTH_PROVIDER_ERROR = "5021", - GITHUB_OAUTH_PROVIDER_ERROR = "5020", + GOOGLE_NOT_CONFIGURED = "5105", + GITHUB_NOT_CONFIGURED = "5110", + GOOGLE_OAUTH_PROVIDER_ERROR = "5115", + GITHUB_OAUTH_PROVIDER_ERROR = "5120", // Reset Password - INVALID_PASSWORD_TOKEN = "5024", - EXPIRED_PASSWORD_TOKEN = "5025", + INVALID_PASSWORD_TOKEN = "5125", + EXPIRED_PASSWORD_TOKEN = "5130", // Change password - INCORRECT_OLD_PASSWORD = "5026", - INVALID_NEW_PASSWORD = "5027", - // set password - PASSWORD_ALREADY_SET = "5028", // used in the onboarding and set password page + INCORRECT_OLD_PASSWORD = "5135", + INVALID_NEW_PASSWORD = "5140", + // set passowrd + PASSWORD_ALREADY_SET = "5145", + // Admin + ADMIN_ALREADY_EXIST = "5150", + REQUIRED_ADMIN_EMAIL_PASSWORD_FIRST_NAME = "5155", + INVALID_ADMIN_EMAIL = "5160", + INVALID_ADMIN_PASSWORD = "5165", + REQUIRED_ADMIN_EMAIL_PASSWORD = "5170", + ADMIN_AUTHENTICATION_FAILED = "5175", + ADMIN_USER_ALREADY_EXIST = "5180", + ADMIN_USER_DOES_NOT_EXIST = "5185", } export type TAuthErrorInfo = { @@ -116,7 +125,7 @@ const errorCodeMessages: { Your account is already registered.  Sign In @@ -191,6 +200,10 @@ const errorCodeMessages: { title: `Expired magic code`, message: () => `Expired magic code. Please try again.`, }, + [EAuthenticationErrorCodes.EMAIL_CODE_ATTEMPT_EXHAUSTED]: { + title: `Expired magic code`, + message: () => `Expired magic code. Please try again.`, + }, // Oauth [EAuthenticationErrorCodes.GOOGLE_NOT_CONFIGURED]: { @@ -235,27 +248,84 @@ const errorCodeMessages: { title: `Password already set`, message: () => `Password already set. Please try again.`, }, + + // admin + [EAuthenticationErrorCodes.ADMIN_ALREADY_EXIST]: { + title: `Admin already exists`, + message: () => `Admin already exists. Please try again.`, + }, + [EAuthenticationErrorCodes.REQUIRED_ADMIN_EMAIL_PASSWORD_FIRST_NAME]: { + title: `Email, password and first name required`, + message: () => `Email, password and first name required. Please try again.`, + }, + [EAuthenticationErrorCodes.INVALID_ADMIN_EMAIL]: { + title: `Invalid admin email`, + message: () => `Invalid admin email. Please try again.`, + }, + [EAuthenticationErrorCodes.INVALID_ADMIN_PASSWORD]: { + title: `Invalid admin password`, + message: () => `Invalid admin password. Please try again.`, + }, + [EAuthenticationErrorCodes.REQUIRED_ADMIN_EMAIL_PASSWORD]: { + title: `Email and password required`, + message: () => `Email and password required. Please try again.`, + }, + [EAuthenticationErrorCodes.ADMIN_AUTHENTICATION_FAILED]: { + title: `Authentication failed`, + message: () => `Authentication failed. Please try again.`, + }, + [EAuthenticationErrorCodes.ADMIN_USER_ALREADY_EXIST]: { + title: `Admin user already exists`, + message: () => ( +
+ Admin user already exists.  + + Sign In + +  now. +
+ ), + }, + [EAuthenticationErrorCodes.ADMIN_USER_DOES_NOT_EXIST]: { + title: `Admin user does not exist`, + message: () => ( +
+ Admin user does not exist.  + + Sign In + +  now. +
+ ), + }, }; export const authErrorHandler = ( errorCode: EAuthenticationErrorCodes, email?: string | undefined ): TAuthErrorInfo | undefined => { - const toastAlertErrorCodes = [ + const bannerAlertErrorCodes = [ + EAuthenticationErrorCodes.INSTANCE_NOT_CONFIGURED, + EAuthenticationErrorCodes.INVALID_EMAIL, + EAuthenticationErrorCodes.EMAIL_REQUIRED, EAuthenticationErrorCodes.SIGNUP_DISABLED, EAuthenticationErrorCodes.INVALID_PASSWORD, EAuthenticationErrorCodes.SMTP_NOT_CONFIGURED, - EAuthenticationErrorCodes.INVALID_EMAIL, - EAuthenticationErrorCodes.EMAIL_REQUIRED, + EAuthenticationErrorCodes.USER_ALREADY_EXIST, EAuthenticationErrorCodes.AUTHENTICATION_FAILED_SIGN_UP, + EAuthenticationErrorCodes.REQUIRED_EMAIL_PASSWORD_SIGN_UP, EAuthenticationErrorCodes.INVALID_EMAIL_SIGN_UP, - EAuthenticationErrorCodes.MAGIC_SIGN_UP_EMAIL_CODE_REQUIRED, EAuthenticationErrorCodes.INVALID_EMAIL_MAGIC_SIGN_UP, + EAuthenticationErrorCodes.MAGIC_SIGN_UP_EMAIL_CODE_REQUIRED, + EAuthenticationErrorCodes.USER_DOES_NOT_EXIST, EAuthenticationErrorCodes.AUTHENTICATION_FAILED_SIGN_IN, + EAuthenticationErrorCodes.REQUIRED_EMAIL_PASSWORD_SIGN_IN, EAuthenticationErrorCodes.INVALID_EMAIL_SIGN_IN, EAuthenticationErrorCodes.INVALID_EMAIL_MAGIC_SIGN_IN, + EAuthenticationErrorCodes.MAGIC_SIGN_IN_EMAIL_CODE_REQUIRED, EAuthenticationErrorCodes.INVALID_MAGIC_CODE, EAuthenticationErrorCodes.EXPIRED_MAGIC_CODE, + EAuthenticationErrorCodes.EMAIL_CODE_ATTEMPT_EXHAUSTED, EAuthenticationErrorCodes.GOOGLE_NOT_CONFIGURED, EAuthenticationErrorCodes.GITHUB_NOT_CONFIGURED, EAuthenticationErrorCodes.GOOGLE_OAUTH_PROVIDER_ERROR, @@ -265,23 +335,15 @@ export const authErrorHandler = ( EAuthenticationErrorCodes.INCORRECT_OLD_PASSWORD, EAuthenticationErrorCodes.INVALID_NEW_PASSWORD, EAuthenticationErrorCodes.PASSWORD_ALREADY_SET, + EAuthenticationErrorCodes.ADMIN_ALREADY_EXIST, + EAuthenticationErrorCodes.REQUIRED_ADMIN_EMAIL_PASSWORD_FIRST_NAME, + EAuthenticationErrorCodes.INVALID_ADMIN_EMAIL, + EAuthenticationErrorCodes.INVALID_ADMIN_PASSWORD, + EAuthenticationErrorCodes.REQUIRED_ADMIN_EMAIL_PASSWORD, + EAuthenticationErrorCodes.ADMIN_AUTHENTICATION_FAILED, + EAuthenticationErrorCodes.ADMIN_USER_ALREADY_EXIST, + EAuthenticationErrorCodes.ADMIN_USER_DOES_NOT_EXIST, ]; - const bannerAlertErrorCodes = [ - EAuthenticationErrorCodes.INSTANCE_NOT_CONFIGURED, - EAuthenticationErrorCodes.USER_ALREADY_EXIST, - EAuthenticationErrorCodes.USER_DOES_NOT_EXIST, - EAuthenticationErrorCodes.REQUIRED_EMAIL_PASSWORD_SIGN_UP, - EAuthenticationErrorCodes.REQUIRED_EMAIL_PASSWORD_SIGN_IN, - EAuthenticationErrorCodes.MAGIC_SIGN_IN_EMAIL_CODE_REQUIRED, - ]; - - if (toastAlertErrorCodes.includes(errorCode)) - return { - type: EErrorAlertType.TOAST_ALERT, - code: errorCode, - title: errorCodeMessages[errorCode]?.title || "Error", - message: errorCodeMessages[errorCode]?.message(email) || "Something went wrong. Please try again.", - }; if (bannerAlertErrorCodes.includes(errorCode)) return { diff --git a/web/lib/wrappers/authentication-wrapper.tsx b/web/lib/wrappers/authentication-wrapper.tsx index 4993846f3d2..b71335bf26f 100644 --- a/web/lib/wrappers/authentication-wrapper.tsx +++ b/web/lib/wrappers/authentication-wrapper.tsx @@ -84,7 +84,7 @@ export const AuthenticationWrapper: FC = observer((props if (pageType === EPageTypes.ONBOARDING) { if (!currentUser?.id) { - router.push("/accounts/sign-in"); + router.push("/sign-in"); return <>; } else { if (currentUser && currentUserProfile?.id && currentUserProfile?.is_onboarded) { @@ -97,7 +97,7 @@ export const AuthenticationWrapper: FC = observer((props if (pageType === EPageTypes.SET_PASSWORD) { if (!currentUser?.id) { - router.push("/accounts/sign-in"); + router.push("/sign-in"); return <>; } else { if ( @@ -121,7 +121,7 @@ export const AuthenticationWrapper: FC = observer((props return <>; } } else { - router.push("/accounts/sign-in"); + router.push("/sign-in"); return <>; } } diff --git a/web/pages/accounts/forgot-password.tsx b/web/pages/accounts/forgot-password.tsx index cb1df8504eb..5334bc15e33 100644 --- a/web/pages/accounts/forgot-password.tsx +++ b/web/pages/accounts/forgot-password.tsx @@ -176,7 +176,7 @@ const ForgotPasswordPage: NextPageWithLayout = () => { > {resendTimerCode > 0 ? `Resend in ${resendTimerCode} seconds` : "Send reset link"} - + Back to sign in diff --git a/web/pages/index.tsx b/web/pages/index.tsx index 6b085ffd3df..5d497abab77 100644 --- a/web/pages/index.tsx +++ b/web/pages/index.tsx @@ -48,7 +48,7 @@ const HomePage: NextPageWithLayout = observer(() => {
Already have an account?{" "} captureEvent(NAVIGATE_TO_SIGNIN, {})} className="font-semibold text-custom-primary-100 hover:underline" > diff --git a/web/pages/accounts/sign-in.tsx b/web/pages/sign-in.tsx similarity index 100% rename from web/pages/accounts/sign-in.tsx rename to web/pages/sign-in.tsx From 15334b07e8ae619bdcba2d0629c001405cdf03a3 Mon Sep 17 00:00:00 2001 From: Anmol Singh Bhatia Date: Fri, 10 May 2024 14:57:31 +0530 Subject: [PATCH 05/12] chore: auth input error indication and autofill styling improvement --- web/components/account/auth-forms/email.tsx | 9 ++++++--- web/components/account/auth-forms/password.tsx | 6 +++--- web/components/account/auth-forms/unique-code.tsx | 4 ++-- web/styles/globals.css | 11 ++++++++++- 4 files changed, 21 insertions(+), 9 deletions(-) diff --git a/web/components/account/auth-forms/email.tsx b/web/components/account/auth-forms/email.tsx index df20d98ff71..923bc5fcf50 100644 --- a/web/components/account/auth-forms/email.tsx +++ b/web/components/account/auth-forms/email.tsx @@ -20,6 +20,7 @@ export const AuthEmailForm: FC = observer((props) => { // states const [isSubmitting, setIsSubmitting] = useState(false); const [email, setEmail] = useState(defaultEmail); + const [isFocused, setFocused] = useState(false); const emailError = useMemo( () => (email && !checkEmailValidity(email) ? { email: "Email is invalid" } : undefined), @@ -47,7 +48,7 @@ export const AuthEmailForm: FC = observer((props) => {
= observer((props) => { value={email} onChange={(e) => setEmail(e.target.value)} placeholder="name@company.com" - className={`h-[46px] w-full placeholder:text-onboarding-text-400 border-0`} + className={`disable-autofill-style h-[46px] w-full placeholder:text-onboarding-text-400 autofill:bg-red-500 border-0 focus:bg-none active:bg-transparent`} + onFocus={() => setFocused(true)} + onBlur={() => setFocused(false)} autoFocus /> {email.length > 0 && ( @@ -66,7 +69,7 @@ export const AuthEmailForm: FC = observer((props) => {
)}
- {emailError?.email && ( + {emailError?.email && !isFocused && (

{emailError.email} diff --git a/web/components/account/auth-forms/password.tsx b/web/components/account/auth-forms/password.tsx index be9e32c8a73..35385ee714c 100644 --- a/web/components/account/auth-forms/password.tsx +++ b/web/components/account/auth-forms/password.tsx @@ -128,7 +128,7 @@ export const AuthPasswordForm: React.FC = observer((props: Props) => { value={passwordFormData.email} onChange={(e) => handleFormChange("email", e.target.value)} placeholder="name@company.com" - className={`h-[46px] w-full placeholder:text-onboarding-text-400 border-0`} + className={`disable-autofill-style h-[46px] w-full placeholder:text-onboarding-text-400 border-0`} disabled /> {passwordFormData.email.length > 0 && ( @@ -150,7 +150,7 @@ export const AuthPasswordForm: React.FC = observer((props: Props) => { value={passwordFormData.password} onChange={(e) => handleFormChange("password", e.target.value)} placeholder="Enter password" - className="h-[46px] w-full border border-onboarding-border-100 !bg-onboarding-background-200 pr-12 placeholder:text-onboarding-text-400" + className="disable-autofill-style h-[46px] w-full border border-onboarding-border-100 !bg-onboarding-background-200 pr-12 placeholder:text-onboarding-text-400" onFocus={() => setIsPasswordInputFocused(true)} onBlur={() => setIsPasswordInputFocused(false)} autoFocus @@ -182,7 +182,7 @@ export const AuthPasswordForm: React.FC = observer((props: Props) => { value={passwordFormData.confirm_password} onChange={(e) => handleFormChange("confirm_password", e.target.value)} placeholder="Confirm password" - className="h-[46px] w-full border border-onboarding-border-100 !bg-onboarding-background-200 pr-12 placeholder:text-onboarding-text-400" + className="disable-autofill-style h-[46px] w-full border border-onboarding-border-100 !bg-onboarding-background-200 pr-12 placeholder:text-onboarding-text-400" /> {showPassword?.retypePassword ? ( = (props) => { value={uniqueCodeFormData.email} onChange={(e) => handleFormChange("email", e.target.value)} placeholder="name@company.com" - className={`h-[46px] w-full placeholder:text-onboarding-text-400 border-0`} + className={`disable-autofill-style h-[46px] w-full placeholder:text-onboarding-text-400 border-0`} disabled /> {uniqueCodeFormData.email.length > 0 && ( @@ -112,7 +112,7 @@ export const AuthUniqueCodeForm: React.FC = (props) => { value={uniqueCodeFormData.code} onChange={(e) => handleFormChange("code", e.target.value)} placeholder="gets-sets-flys" - className="h-[46px] w-full border border-onboarding-border-100 !bg-onboarding-background-200 pr-12 placeholder:text-onboarding-text-400" + className="disable-autofill-style h-[46px] w-full border border-onboarding-border-100 !bg-onboarding-background-200 pr-12 placeholder:text-onboarding-text-400" autoFocus />

diff --git a/web/styles/globals.css b/web/styles/globals.css index b27d3ef4536..09e3b9c0874 100644 --- a/web/styles/globals.css +++ b/web/styles/globals.css @@ -640,4 +640,13 @@ div.web-view-spinner div.bar12 { .highlight-with-line { border-left: 5px solid rgb(var(--color-primary-100)) !important; background: rgb(var(--color-background-80)); -} \ No newline at end of file +} + +/* By applying below class, the autofilled text in form fields will not have the default autofill background color and styles applied by WebKit browsers */ + +.disable-autofill-style:-webkit-autofill, +.disable-autofill-style:-webkit-autofill:hover, +.disable-autofill-style:-webkit-autofill:focus, +.disable-autofill-style:-webkit-autofill:active { + -webkit-background-clip: text; +} From 330812a3b84fbaae65720f1213ccfe2c442e603c Mon Sep 17 00:00:00 2001 From: pablohashescobar Date: Fri, 10 May 2024 15:04:33 +0530 Subject: [PATCH 06/12] dev: add app redirection urls --- apiserver/plane/authentication/utils/host.py | 5 +++- apiserver/plane/authentication/utils/login.py | 9 ++++-- .../plane/authentication/views/app/email.py | 28 +++++++++---------- .../plane/authentication/views/app/github.py | 8 +++--- .../plane/authentication/views/app/google.py | 8 +++--- .../plane/authentication/views/app/magic.py | 20 ++++++------- .../views/app/password_management.py | 10 +++---- .../plane/authentication/views/app/signout.py | 11 ++++---- .../plane/authentication/views/common.py | 4 +-- .../plane/authentication/views/space/email.py | 4 +-- .../authentication/views/space/github.py | 4 +-- .../authentication/views/space/google.py | 2 +- .../plane/authentication/views/space/magic.py | 4 +-- apiserver/plane/license/api/views/admin.py | 4 +-- apiserver/plane/settings/common.py | 2 +- 15 files changed, 65 insertions(+), 58 deletions(-) diff --git a/apiserver/plane/authentication/utils/host.py b/apiserver/plane/authentication/utils/host.py index b670eed41ca..d9b2b908732 100644 --- a/apiserver/plane/authentication/utils/host.py +++ b/apiserver/plane/authentication/utils/host.py @@ -5,7 +5,7 @@ from django.conf import settings -def base_host(request, is_admin=False, is_space=False): +def base_host(request, is_admin=False, is_space=False, is_app=False): """Utility function to return host / origin from the request""" if is_admin and settings.ADMIN_BASE_URL: @@ -14,6 +14,9 @@ def base_host(request, is_admin=False, is_space=False): if is_space and settings.SPACE_BASE_URL: return settings.SPACE_BASE_URL + if is_app and settings.APP_BASE_URL: + return settings.APP_BASE_URL + return ( request.META.get("HTTP_ORIGIN") or f"{urlsplit(request.META.get('HTTP_REFERER')).scheme}://{urlsplit(request.META.get('HTTP_REFERER')).netloc}" diff --git a/apiserver/plane/authentication/utils/login.py b/apiserver/plane/authentication/utils/login.py index 88a988c8f58..45dbdc24943 100644 --- a/apiserver/plane/authentication/utils/login.py +++ b/apiserver/plane/authentication/utils/login.py @@ -5,12 +5,17 @@ from plane.authentication.utils.host import base_host -def user_login(request, user): +def user_login(request, user, is_app=False, is_admin=False, is_space=False): login(request=request, user=user) device_info = { "user_agent": request.META.get("HTTP_USER_AGENT", ""), "ip_address": request.META.get("REMOTE_ADDR", ""), - "domain": base_host(request=request), + "domain": base_host( + request=request, + is_app=is_app, + is_admin=is_admin, + is_space=is_space, + ), } request.session["device_info"] = device_info request.session.save() diff --git a/apiserver/plane/authentication/views/app/email.py b/apiserver/plane/authentication/views/app/email.py index 14d2c64d03c..4093be1080c 100644 --- a/apiserver/plane/authentication/views/app/email.py +++ b/apiserver/plane/authentication/views/app/email.py @@ -42,7 +42,7 @@ def post(self, request): params["next_path"] = str(next_path) # Base URL join url = urljoin( - base_host(request=request), + base_host(request=request, is_app=True), "sign-in?" + urlencode(params), ) return HttpResponseRedirect(url) @@ -66,7 +66,7 @@ def post(self, request): if next_path: params["next_path"] = str(next_path) url = urljoin( - base_host(request=request), + base_host(request=request, is_app=True), "sign-in?" + urlencode(params), ) return HttpResponseRedirect(url) @@ -85,7 +85,7 @@ def post(self, request): if next_path: params["next_path"] = str(next_path) url = urljoin( - base_host(request=request), + base_host(request=request, is_app=True), "sign-in?" + urlencode(params), ) return HttpResponseRedirect(url) @@ -100,7 +100,7 @@ def post(self, request): if next_path: params["next_path"] = str(next_path) url = urljoin( - base_host(request=request), + base_host(request=request, is_app=True), "sign-in?" + urlencode(params), ) return HttpResponseRedirect(url) @@ -111,7 +111,7 @@ def post(self, request): ) user = provider.authenticate() # Login the user and record his device info - user_login(request=request, user=user) + user_login(request=request, user=user, is_app=True) # Process workspace and project invitations process_workspace_project_invitations(user=user) # Get the redirection path @@ -121,14 +121,14 @@ def post(self, request): path = get_redirection_path(user=user) # redirect to referer path - url = urljoin(base_host(request=request), path) + url = urljoin(base_host(request=request, is_app=True), path) return HttpResponseRedirect(url) except AuthenticationException as e: params = e.get_error_dict() if next_path: params["next_path"] = str(next_path) url = urljoin( - base_host(request=request), + base_host(request=request, is_app=True), "sign-in?" + urlencode(params), ) return HttpResponseRedirect(url) @@ -152,7 +152,7 @@ def post(self, request): if next_path: params["next_path"] = str(next_path) url = urljoin( - base_host(request=request), + base_host(request=request, is_app=True), "?" + urlencode(params), ) return HttpResponseRedirect(url) @@ -173,7 +173,7 @@ def post(self, request): if next_path: params["next_path"] = str(next_path) url = urljoin( - base_host(request=request), + base_host(request=request, is_app=True), "?" + urlencode(params), ) return HttpResponseRedirect(url) @@ -192,7 +192,7 @@ def post(self, request): if next_path: params["next_path"] = str(next_path) url = urljoin( - base_host(request=request), + base_host(request=request, is_app=True), "?" + urlencode(params), ) return HttpResponseRedirect(url) @@ -207,7 +207,7 @@ def post(self, request): if next_path: params["next_path"] = str(next_path) url = urljoin( - base_host(request=request), + base_host(request=request, is_app=True), "?" + urlencode(params), ) return HttpResponseRedirect(url) @@ -218,7 +218,7 @@ def post(self, request): ) user = provider.authenticate() # Login the user and record his device info - user_login(request=request, user=user) + user_login(request=request, user=user, is_app=True) # Process workspace and project invitations process_workspace_project_invitations(user=user) # Get the redirection path @@ -227,14 +227,14 @@ def post(self, request): else: path = get_redirection_path(user=user) # redirect to referer path - url = urljoin(base_host(request=request), path) + url = urljoin(base_host(request=request, is_app=True), path) return HttpResponseRedirect(url) except AuthenticationException as e: params = e.get_error_dict() if next_path: params["next_path"] = str(next_path) url = urljoin( - base_host(request=request), + base_host(request=request, is_app=True), "?" + urlencode(params), ) return HttpResponseRedirect(url) diff --git a/apiserver/plane/authentication/views/app/github.py b/apiserver/plane/authentication/views/app/github.py index 48b7e09d96e..73afa674b99 100644 --- a/apiserver/plane/authentication/views/app/github.py +++ b/apiserver/plane/authentication/views/app/github.py @@ -24,7 +24,7 @@ class GitHubOauthInitiateEndpoint(View): def get(self, request): # Get host and next path - request.session["host"] = base_host(request=request) + request.session["host"] = base_host(request=request, is_app=True) next_path = request.GET.get("next_path") if next_path: request.session["next_path"] = str(next_path) @@ -42,7 +42,7 @@ def get(self, request): if next_path: params["next_path"] = str(next_path) url = urljoin( - base_host(request=request), + base_host(request=request, is_app=True), "?" + urlencode(params), ) return HttpResponseRedirect(url) @@ -57,7 +57,7 @@ def get(self, request): if next_path: params["next_path"] = str(next_path) url = urljoin( - base_host(request=request), + base_host(request=request, is_app=True), "?" + urlencode(params), ) return HttpResponseRedirect(url) @@ -110,7 +110,7 @@ def get(self, request): ) user = provider.authenticate() # Login the user and record his device info - user_login(request=request, user=user) + user_login(request=request, user=user, is_app=True) # Process workspace and project invitations process_workspace_project_invitations(user=user) # Get the redirection path diff --git a/apiserver/plane/authentication/views/app/google.py b/apiserver/plane/authentication/views/app/google.py index 690a9778bd7..ea3afed896c 100644 --- a/apiserver/plane/authentication/views/app/google.py +++ b/apiserver/plane/authentication/views/app/google.py @@ -24,7 +24,7 @@ class GoogleOauthInitiateEndpoint(View): def get(self, request): - request.session["host"] = base_host(request=request) + request.session["host"] = base_host(request=request, is_app=True) next_path = request.GET.get("next_path") if next_path: request.session["next_path"] = str(next_path) @@ -42,7 +42,7 @@ def get(self, request): if next_path: params["next_path"] = str(next_path) url = urljoin( - base_host(request=request), + base_host(request=request, is_app=True), "?" + urlencode(params), ) return HttpResponseRedirect(url) @@ -58,7 +58,7 @@ def get(self, request): if next_path: params["next_path"] = str(next_path) url = urljoin( - base_host(request=request), + base_host(request=request, is_app=True), "?" + urlencode(params), ) return HttpResponseRedirect(url) @@ -108,7 +108,7 @@ def get(self, request): ) user = provider.authenticate() # Login the user and record his device info - user_login(request=request, user=user) + user_login(request=request, user=user, is_app=True) # Process workspace and project invitations process_workspace_project_invitations(user=user) # Get the redirection path diff --git a/apiserver/plane/authentication/views/app/magic.py b/apiserver/plane/authentication/views/app/magic.py index 9050f051c53..0fa5296740e 100644 --- a/apiserver/plane/authentication/views/app/magic.py +++ b/apiserver/plane/authentication/views/app/magic.py @@ -90,7 +90,7 @@ def post(self, request): if next_path: params["next_path"] = str(next_path) url = urljoin( - base_host(request=request), + base_host(request=request, is_app=True), "sign-in?" + urlencode(params), ) return HttpResponseRedirect(url) @@ -104,7 +104,7 @@ def post(self, request): if next_path: params["next_path"] = str(next_path) url = urljoin( - base_host(request=request), + base_host(request=request, is_app=True), "sign-in?" + urlencode(params), ) return HttpResponseRedirect(url) @@ -116,7 +116,7 @@ def post(self, request): user = provider.authenticate() profile = Profile.objects.get(user=user) # Login the user and record his device info - user_login(request=request, user=user) + user_login(request=request, user=user, is_app=True) # Process workspace and project invitations process_workspace_project_invitations(user=user) if user.is_password_autoset and profile.is_onboarded: @@ -129,7 +129,7 @@ def post(self, request): else str(process_workspace_project_invitations(user=user)) ) # redirect to referer path - url = urljoin(base_host(request=request), path) + url = urljoin(base_host(request=request, is_app=True), path) return HttpResponseRedirect(url) except AuthenticationException as e: @@ -137,7 +137,7 @@ def post(self, request): if next_path: params["next_path"] = str(next_path) url = urljoin( - base_host(request=request), + base_host(request=request, is_app=True), "sign-in?" + urlencode(params), ) return HttpResponseRedirect(url) @@ -163,7 +163,7 @@ def post(self, request): if next_path: params["next_path"] = str(next_path) url = urljoin( - base_host(request=request), + base_host(request=request, is_app=True), "?" + urlencode(params), ) return HttpResponseRedirect(url) @@ -177,7 +177,7 @@ def post(self, request): if next_path: params["next_path"] = str(next_path) url = urljoin( - base_host(request=request), + base_host(request=request, is_app=True), "?" + urlencode(params), ) return HttpResponseRedirect(url) @@ -188,7 +188,7 @@ def post(self, request): ) user = provider.authenticate() # Login the user and record his device info - user_login(request=request, user=user) + user_login(request=request, user=user, is_app=True) # Process workspace and project invitations process_workspace_project_invitations(user=user) # Get the redirection path @@ -197,7 +197,7 @@ def post(self, request): else: path = get_redirection_path(user=user) # redirect to referer path - url = urljoin(base_host(request=request), path) + url = urljoin(base_host(request=request, is_app=True), path) return HttpResponseRedirect(url) except AuthenticationException as e: @@ -205,7 +205,7 @@ def post(self, request): if next_path: params["next_path"] = str(next_path) url = urljoin( - base_host(request=request), + base_host(request=request, is_app=True), "?" + urlencode(params), ) return HttpResponseRedirect(url) diff --git a/apiserver/plane/authentication/views/app/password_management.py b/apiserver/plane/authentication/views/app/password_management.py index 152605cc05a..b26b5776066 100644 --- a/apiserver/plane/authentication/views/app/password_management.py +++ b/apiserver/plane/authentication/views/app/password_management.py @@ -146,7 +146,7 @@ def post(self, request, uidb64, token): ) params = exc.get_error_dict() url = urljoin( - base_host(request=request), + base_host(request=request, is_app=True), "accounts/reset-password?" + urlencode(params), ) return HttpResponseRedirect(url) @@ -159,7 +159,7 @@ def post(self, request, uidb64, token): error_message="INVALID_PASSWORD", ) url = urljoin( - base_host(request=request), + base_host(request=request, is_app=True), "accounts/reset-password?" + urlencode(exc.get_error_dict()), ) @@ -173,7 +173,7 @@ def post(self, request, uidb64, token): error_message="INVALID_PASSWORD", ) url = urljoin( - base_host(request=request), + base_host(request=request, is_app=True), "accounts/reset-password?" + urlencode(exc.get_error_dict()), ) @@ -185,7 +185,7 @@ def post(self, request, uidb64, token): user.save() url = urljoin( - base_host(request=request), + base_host(request=request, is_app=True), "sign-in?" + urlencode({"success": True}), ) return HttpResponseRedirect(url) @@ -197,7 +197,7 @@ def post(self, request, uidb64, token): error_message="EXPIRED_PASSWORD_TOKEN", ) url = urljoin( - base_host(request=request), + base_host(request=request, is_app=True), "accounts/reset-password?" + urlencode(exc.get_error_dict()), ) return HttpResponseRedirect(url) diff --git a/apiserver/plane/authentication/views/app/signout.py b/apiserver/plane/authentication/views/app/signout.py index b8d36dd1a28..10461f240df 100644 --- a/apiserver/plane/authentication/views/app/signout.py +++ b/apiserver/plane/authentication/views/app/signout.py @@ -1,5 +1,5 @@ # Python imports -from urllib.parse import urlencode, urljoin +from urllib.parse import urljoin # Django imports from django.views import View @@ -23,10 +23,9 @@ def post(self, request): user.save() # Log the user out logout(request) - url = urljoin( - base_host(request=request), - "sign-in?" + urlencode({"success": "true"}), - ) + url = urljoin(base_host(request=request, is_app=True), "sign-in") return HttpResponseRedirect(url) except Exception: - return HttpResponseRedirect(base_host(request=request), "sign-in") + return HttpResponseRedirect( + base_host(request=request, is_app=True), "sign-in" + ) diff --git a/apiserver/plane/authentication/views/common.py b/apiserver/plane/authentication/views/common.py index 4b93010de58..16ac058b02b 100644 --- a/apiserver/plane/authentication/views/common.py +++ b/apiserver/plane/authentication/views/common.py @@ -70,7 +70,7 @@ def post(self, request): user.set_password(serializer.data.get("new_password")) user.is_password_autoset = False user.save() - user_login(user=user, request=request) + user_login(user=user, request=request, is_app=True) return Response( {"message": "Password updated successfully"}, status=status.HTTP_200_OK, @@ -131,7 +131,7 @@ def post(self, request): user.is_password_autoset = False user.save() # Login the user as the session is invalidated - user_login(user=user, request=request) + user_login(user=user, request=request, is_app=True) # Return the user serializer = UserSerializer(user) return Response(serializer.data, status=status.HTTP_200_OK) diff --git a/apiserver/plane/authentication/views/space/email.py b/apiserver/plane/authentication/views/space/email.py index 9270fd1ea6f..e11ab29b510 100644 --- a/apiserver/plane/authentication/views/space/email.py +++ b/apiserver/plane/authentication/views/space/email.py @@ -104,7 +104,7 @@ def post(self, request): ) user = provider.authenticate() # Login the user and record his device info - user_login(request=request, user=user) + user_login(request=request, user=user, is_space=True) # redirect to next path url = urljoin( base_host(request=request, is_space=True), @@ -206,7 +206,7 @@ def post(self, request): ) user = provider.authenticate() # Login the user and record his device info - user_login(request=request, user=user) + user_login(request=request, user=user, is_space=True) # redirect to referer path url = urljoin( base_host(request=request, is_space=True), diff --git a/apiserver/plane/authentication/views/space/github.py b/apiserver/plane/authentication/views/space/github.py index 58c1f5f908e..8430cbdfb03 100644 --- a/apiserver/plane/authentication/views/space/github.py +++ b/apiserver/plane/authentication/views/space/github.py @@ -55,7 +55,7 @@ def get(self, request): if next_path: params["next_path"] = str(next_path) url = urljoin( - base_host(request=request), + base_host(request=request, is_space=True), "?" + urlencode(params), ) return HttpResponseRedirect(url) @@ -108,7 +108,7 @@ def get(self, request): ) user = provider.authenticate() # Login the user and record his device info - user_login(request=request, user=user) + user_login(request=request, user=user, is_space=True) # Process workspace and project invitations # redirect to referer path url = urljoin(base_host, str(next_path) if next_path else "") diff --git a/apiserver/plane/authentication/views/space/google.py b/apiserver/plane/authentication/views/space/google.py index 2f6b576993f..502f146c31d 100644 --- a/apiserver/plane/authentication/views/space/google.py +++ b/apiserver/plane/authentication/views/space/google.py @@ -103,7 +103,7 @@ def get(self, request): ) user = provider.authenticate() # Login the user and record his device info - user_login(request=request, user=user) + user_login(request=request, user=user, is_space=True) # redirect to referer path url = urljoin( base_host, str(next_path) if next_path else "/spaces" diff --git a/apiserver/plane/authentication/views/space/magic.py b/apiserver/plane/authentication/views/space/magic.py index fc1281c4bf1..45a8e375503 100644 --- a/apiserver/plane/authentication/views/space/magic.py +++ b/apiserver/plane/authentication/views/space/magic.py @@ -109,7 +109,7 @@ def post(self, request): ) user = provider.authenticate() # Login the user and record his device info - user_login(request=request, user=user) + user_login(request=request, user=user, is_space=True) # redirect to referer path profile = Profile.objects.get(user=user) if user.is_password_autoset and profile.is_onboarded: @@ -176,7 +176,7 @@ def post(self, request): ) user = provider.authenticate() # Login the user and record his device info - user_login(request=request, user=user) + user_login(request=request, user=user, is_space=True) # redirect to referer path url = urljoin( base_host(request=request, is_space=True), diff --git a/apiserver/plane/license/api/views/admin.py b/apiserver/plane/license/api/views/admin.py index 490d0d2ca64..832edec417c 100644 --- a/apiserver/plane/license/api/views/admin.py +++ b/apiserver/plane/license/api/views/admin.py @@ -247,7 +247,7 @@ def post(self, request): instance.save() # get tokens for user - user_login(request=request, user=user) + user_login(request=request, user=user, is_admin=True) url = urljoin(base_host(request=request, is_admin=True), "general") return HttpResponseRedirect(url) @@ -376,7 +376,7 @@ def post(self, request): user.save() # get tokens for user - user_login(request=request, user=user) + user_login(request=request, user=user, is_admin=True) url = urljoin(base_host(request=request, is_admin=True), "general") return HttpResponseRedirect(url) diff --git a/apiserver/plane/settings/common.py b/apiserver/plane/settings/common.py index 4f5e6d4eef1..f043340a297 100644 --- a/apiserver/plane/settings/common.py +++ b/apiserver/plane/settings/common.py @@ -346,4 +346,4 @@ # Base URLs ADMIN_BASE_URL = os.environ.get("ADMIN_BASE_URL", None) SPACE_BASE_URL = os.environ.get("SPACE_BASE_URL", None) -APP_BASE_URL = os.environ.get("ADMIN_BASE_URL", None) +APP_BASE_URL = os.environ.get("APP_BASE_URL") or os.environ.get("WEB_URL") From 4c865ef9b9ea2f432a4b398d7cf0ca9e8487043b Mon Sep 17 00:00:00 2001 From: pablohashescobar Date: Fri, 10 May 2024 15:49:41 +0530 Subject: [PATCH 07/12] dev: update redirections --- admin/Dockerfile.admin | 4 +-- apiserver/plane/authentication/utils/host.py | 38 ++++++++++++++------ apiserver/plane/license/api/views/admin.py | 7 ++-- web/Dockerfile.web | 8 ++--- 4 files changed, 35 insertions(+), 22 deletions(-) diff --git a/admin/Dockerfile.admin b/admin/Dockerfile.admin index 901c39e27d7..b2908f356cb 100644 --- a/admin/Dockerfile.admin +++ b/admin/Dockerfile.admin @@ -32,7 +32,7 @@ ENV NEXT_PUBLIC_API_BASE_URL=$NEXT_PUBLIC_API_BASE_URL ARG NEXT_PUBLIC_WEB_BASE_URL="" ENV NEXT_PUBLIC_WEB_BASE_URL=$NEXT_PUBLIC_WEB_BASE_URL -ARG NEXT_PUBLIC_SPACE_BASE_URL="" +ARG NEXT_PUBLIC_SPACE_BASE_URL="/spaces" ENV NEXT_PUBLIC_SPACE_BASE_URL=$NEXT_PUBLIC_SPACE_BASE_URL ARG NEXT_PUBLIC_ADMIN_BASE_PATH="/god-mode" @@ -62,7 +62,7 @@ ENV NEXT_PUBLIC_API_BASE_URL=$NEXT_PUBLIC_API_BASE_URL ARG NEXT_PUBLIC_WEB_BASE_URL="" ENV NEXT_PUBLIC_WEB_BASE_URL=$NEXT_PUBLIC_WEB_BASE_URL -ARG NEXT_PUBLIC_SPACE_BASE_URL="" +ARG NEXT_PUBLIC_SPACE_BASE_URL="/spaces" ENV NEXT_PUBLIC_SPACE_BASE_URL=$NEXT_PUBLIC_SPACE_BASE_URL ARG NEXT_PUBLIC_ADMIN_BASE_PATH="/god-mode" diff --git a/apiserver/plane/authentication/utils/host.py b/apiserver/plane/authentication/utils/host.py index d9b2b908732..d8c7c7a16b7 100644 --- a/apiserver/plane/authentication/utils/host.py +++ b/apiserver/plane/authentication/utils/host.py @@ -7,21 +7,37 @@ def base_host(request, is_admin=False, is_space=False, is_app=False): """Utility function to return host / origin from the request""" - - if is_admin and settings.ADMIN_BASE_URL: - return settings.ADMIN_BASE_URL - - if is_space and settings.SPACE_BASE_URL: - return settings.SPACE_BASE_URL - - if is_app and settings.APP_BASE_URL: - return settings.APP_BASE_URL - - return ( + # Calculate the base origin from request + base_origin = ( request.META.get("HTTP_ORIGIN") or f"{urlsplit(request.META.get('HTTP_REFERER')).scheme}://{urlsplit(request.META.get('HTTP_REFERER')).netloc}" or f"""{"https" if request.is_secure() else "http"}://{request.get_host()}""" ) + print( + settings.ADMIN_BASE_URL, settings.SPACE_BASE_URL, settings.APP_BASE_URL + ) + + # Admin redirections + if is_admin: + if settings.ADMIN_BASE_URL: + return settings.ADMIN_BASE_URL + else: + return base_origin + "/god-mode" + + # Space redirections + if is_space: + if settings.SPACE_BASE_URL: + return settings.SPACE_BASE_URL + else: + return base_origin + "/god-mode" + + if is_app: + if settings.APP_BASE_URL: + return settings.APP_BASE_URL + else: + return base_origin + + return base_origin def user_ip(request): diff --git a/apiserver/plane/license/api/views/admin.py b/apiserver/plane/license/api/views/admin.py index 832edec417c..945f4b1b172 100644 --- a/apiserver/plane/license/api/views/admin.py +++ b/apiserver/plane/license/api/views/admin.py @@ -410,12 +410,9 @@ def post(self, request): user.save() # Log the user out logout(request) - url = urljoin( - base_host(request=request, is_admin=True), - "accounts/sign-in?" + urlencode({"success": "true"}), - ) + url = urljoin(base_host(request=request, is_admin=True)) return HttpResponseRedirect(url) except Exception: return HttpResponseRedirect( - base_host(request=request, is_admin=True), "accounts/sign-in" + base_host(request=request, is_admin=True) ) diff --git a/web/Dockerfile.web b/web/Dockerfile.web index 3326fc7511f..6c5655b18ae 100644 --- a/web/Dockerfile.web +++ b/web/Dockerfile.web @@ -36,13 +36,13 @@ ENV NEXT_PUBLIC_API_BASE_URL=$NEXT_PUBLIC_API_BASE_URL ARG NEXT_PUBLIC_ADMIN_BASE_URL="" ENV NEXT_PUBLIC_ADMIN_BASE_URL=$NEXT_PUBLIC_ADMIN_BASE_URL -ARG NEXT_PUBLIC_ADMIN_BASE_PATH="" +ARG NEXT_PUBLIC_ADMIN_BASE_PATH="/god-mode" ENV NEXT_PUBLIC_ADMIN_BASE_PATH=$NEXT_PUBLIC_ADMIN_BASE_PATH ARG NEXT_PUBLIC_SPACE_BASE_URL="" ENV NEXT_PUBLIC_SPACE_BASE_URL=$NEXT_PUBLIC_SPACE_BASE_URL -ARG NEXT_PUBLIC_SPACE_BASE_PATH="" +ARG NEXT_PUBLIC_SPACE_BASE_PATH="/spaces" ENV NEXT_PUBLIC_SPACE_BASE_PATH=$NEXT_PUBLIC_SPACE_BASE_PATH ENV NEXT_TELEMETRY_DISABLED 1 @@ -71,10 +71,10 @@ ENV NEXT_PUBLIC_API_BASE_URL=$NEXT_PUBLIC_API_BASE_URL ARG NEXT_PUBLIC_ADMIN_BASE_URL="" ENV NEXT_PUBLIC_ADMIN_BASE_URL=$NEXT_PUBLIC_ADMIN_BASE_URL -ARG NEXT_PUBLIC_ADMIN_BASE_PATH="" +ARG NEXT_PUBLIC_ADMIN_BASE_PATH="/god-mode" ENV NEXT_PUBLIC_ADMIN_BASE_PATH=$NEXT_PUBLIC_ADMIN_BASE_PATH -ARG NEXT_PUBLIC_SPACE_BASE_URL="" +ARG NEXT_PUBLIC_SPACE_BASE_URL="/spaces" ENV NEXT_PUBLIC_SPACE_BASE_URL=$NEXT_PUBLIC_SPACE_BASE_URL ARG NEXT_PUBLIC_SPACE_BASE_PATH="" From 94917b8b29621e0bd65be0d8cdf2a261b3674945 Mon Sep 17 00:00:00 2001 From: Anmol Singh Bhatia Date: Fri, 10 May 2024 15:50:17 +0530 Subject: [PATCH 08/12] chore: onboarding improvement --- .../onboarding/create-workspace.tsx | 15 +++++++++++--- web/components/onboarding/invite-members.tsx | 1 + web/components/onboarding/profile-setup.tsx | 20 +++++++++++++++---- web/layouts/auth-layout/workspace-wrapper.tsx | 2 +- 4 files changed, 30 insertions(+), 8 deletions(-) diff --git a/web/components/onboarding/create-workspace.tsx b/web/components/onboarding/create-workspace.tsx index 9550043c0d9..eaedf229cec 100644 --- a/web/components/onboarding/create-workspace.tsx +++ b/web/components/onboarding/create-workspace.tsx @@ -148,7 +148,10 @@ export const CreateWorkspace: React.FC = (props) => {
-
-

-