Skip to content

Commit

Permalink
Merge branch 'feat/new-login' into deploy/dev
Browse files Browse the repository at this point in the history
* feat/new-login: (27 commits)
  chore: format
  feat: add fulfill_login_params_from_env
  feat: update message
  feat: update mismatch description
  feat: remove env example
  chore: PLR6201 Use a set literal when testing for membership
  feat: update EmailOrPasswordMismatchError
  feat: allow users to specify timeout for text generations and workflows by environment variable (#8395)
  Fix: operation postion of answer in logs (#8411)
  fix: when the variable does not exist, an error should be prompted (#8413)
  fix(workflow): the answer node after the iteration node containing the answer was output prematurely (#8419)
  fix:logs and rm unused codes in CacheEmbedding (#8409)
  fix: resolve runtime error when self.folder is None (#8401)
  Fix: Support Bedrock cross region inference #8190 (Update Model name to distinguish between different region groups) (#8402)
  fix(docker): aliyun oss path env key (#8394)
  fix: pyproject.toml typo (#8396)
  fix: o1-mini 65563 -> 65536 (#8388)
  fix: sandbox issue related httpx and requests (#8397)
  chore: improve usage of striping prefix or suffix of string with Ruff 0.6.5 (#8392)
  fix (#8322 followup): resolve the violation of pylint rules (#8391)
  ...
  • Loading branch information
ZhouhaoJiang committed Sep 14, 2024
2 parents ff4eb9d + b529ba9 commit dbe759d
Show file tree
Hide file tree
Showing 188 changed files with 836 additions and 899 deletions.
10 changes: 1 addition & 9 deletions api/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -289,12 +289,4 @@ POSITION_TOOL_EXCLUDES=

POSITION_PROVIDER_PINS=
POSITION_PROVIDER_INCLUDES=
POSITION_PROVIDER_EXCLUDES=

# Login
ENABLE_EMAIL_CODE_LOGIN=true
ENABLE_EMAIL_PASSWORD_LOGIN=true
ENABLE_SOCIAL_OAUTH_LOGIN=true
EMAIL_CODE_LOGIN_TOKEN_EXPIRY_HOURS=0.0833
ALLOW_REGISTER=true
ALLOW_CREATE_WORKSPACE=true
POSITION_PROVIDER_EXCLUDES=
2 changes: 1 addition & 1 deletion api/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ def initialize_extensions(app):
@login_manager.request_loader
def load_user_from_request(request_from_flask_login):
"""Load user based on the request."""
if request.blueprint not in ["console", "inner_api"]:
if request.blueprint not in {"console", "inner_api"}:
return None
# Check if the user_id contains a dot, indicating the old format
auth_header = request.headers.get("Authorization", "")
Expand Down
4 changes: 2 additions & 2 deletions api/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,9 +140,9 @@ def reset_encrypt_key_pair():
@click.command("vdb-migrate", help="migrate vector db.")
@click.option("--scope", default="all", prompt=False, help="The scope of vector database to migrate, Default is All.")
def vdb_migrate(scope: str):
if scope in ["knowledge", "all"]:
if scope in {"knowledge", "all"}:
migrate_knowledge_vector_database()
if scope in ["annotation", "all"]:
if scope in {"annotation", "all"}:
migrate_annotation_vector_database()


Expand Down
4 changes: 2 additions & 2 deletions api/configs/feature/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -616,15 +616,15 @@ def POSITION_TOOL_EXCLUDES_SET(self) -> set[str]:
class LoginConfig(BaseSettings):
ENABLE_EMAIL_CODE_LOGIN: bool = Field(
description="whether to enable email code login",
default=True,
default=False,
)
ENABLE_EMAIL_PASSWORD_LOGIN: bool = Field(
description="whether to enable email password login",
default=True,
)
ENABLE_SOCIAL_OAUTH_LOGIN: bool = Field(
description="whether to enable github/google oauth login",
default=True,
default=False,
)
EMAIL_CODE_LOGIN_TOKEN_EXPIRY_HOURS: PositiveFloat = Field(
description="expiry time in hours for email code login token",
Expand Down
2 changes: 1 addition & 1 deletion api/controllers/console/app/audio.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ def post(self, app_model):
message_id = args.get("message_id", None)
text = args.get("text", None)
if (
app_model.mode in [AppMode.ADVANCED_CHAT.value, AppMode.WORKFLOW.value]
app_model.mode in {AppMode.ADVANCED_CHAT.value, AppMode.WORKFLOW.value}
and app_model.workflow
and app_model.workflow.features_dict
):
Expand Down
8 changes: 7 additions & 1 deletion api/controllers/console/auth/error.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,17 @@ class InvalidTokenError(BaseHTTPException):

class PasswordResetRateLimitExceededError(BaseHTTPException):
error_code = "password_reset_rate_limit_exceeded"
description = "Password reset rate limit exceeded. Try again later."
description = "Too many password reset emails have been sent. Please try again in 5 minutes."
code = 429


class EmailCodeError(BaseHTTPException):
error_code = "email_code_error"
description = "Email code is invalid or expired."
code = 400


class EmailOrPasswordMismatchError(BaseHTTPException):
error_code = "email_or_password_mismatch"
description = "The email or password is mismatched."
code = 400
7 changes: 4 additions & 3 deletions api/controllers/console/auth/login.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@
from controllers.console import api
from controllers.console.auth.error import (
EmailCodeError,
EmailOrPasswordMismatchError,
InvalidEmailError,
InvalidTokenError,
PasswordMismatchError,
)
from controllers.console.error import NotAllowedCreateWorkspace, NotAllowedRegister
from controllers.console.setup import setup_required
Expand Down Expand Up @@ -41,7 +41,7 @@ def post(self):
except services.errors.account.AccountLoginError:
raise NotAllowedRegister()
except services.errors.account.AccountPasswordError:
raise PasswordMismatchError()
raise EmailOrPasswordMismatchError()
except services.errors.account.AccountNotFoundError:
if not dify_config.ALLOW_REGISTER:
raise NotAllowedRegister()
Expand Down Expand Up @@ -150,7 +150,8 @@ def post(self):
)
except WorkSpaceNotAllowedCreateError:
return redirect(
f"{dify_config.CONSOLE_WEB_URL}/signin?message=Workspace not found, please contact system admin to invite you to join in a workspace."
f"{dify_config.CONSOLE_WEB_URL}/signin"
"?message=Workspace not found, please contact system admin to invite you to join in a workspace."
)
token = AccountService.login(account, ip_address=get_remote_ip(request))

Expand Down
19 changes: 11 additions & 8 deletions api/controllers/console/auth/oauth.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,23 +84,24 @@ def get(self, provider: str):
if invitation:
invitation_email = invitation.get("email", None)
if invitation_email != user_info.email:
return redirect(f"{dify_config.CONSOLE_WEB_URL}/signin?message=InvalidToken")
return redirect(f"{dify_config.CONSOLE_WEB_URL}/signin?message=Invalid invitation token.")

return redirect(f"{dify_config.CONSOLE_WEB_URL}/signin/invite-settings?invite_token={invite_token}")

try:
account = _generate_account(provider, user_info)
except AccountNotFoundError:
return redirect(f"{dify_config.CONSOLE_WEB_URL}/signin?message=AccountNotFound")
return redirect(f"{dify_config.CONSOLE_WEB_URL}/signin?message=Account not found.")
except WorkSpaceNotFoundError:
return redirect(f"{dify_config.CONSOLE_WEB_URL}/signin?message=WorkspaceNotFound")
return redirect(f"{dify_config.CONSOLE_WEB_URL}/signin?message=Workspace not found.")
except WorkSpaceNotAllowedCreateError:
return redirect(
f"{dify_config.CONSOLE_WEB_URL}/signin?message=Workspace not found, please contact system admin to invite you to join in a workspace."
f"{dify_config.CONSOLE_WEB_URL}/signin"
"?message=Workspace not found, please contact system admin to invite you to join in a workspace."
)

# Check account status
if account.status == AccountStatus.BANNED.value or account.status == AccountStatus.CLOSED.value:
if account.status in {AccountStatus.BANNED.value, AccountStatus.CLOSED.value}:
return {"error": "Account is banned or closed."}, 403

if account.status == AccountStatus.PENDING.value:
Expand All @@ -111,10 +112,11 @@ def get(self, provider: str):
try:
TenantService.create_owner_tenant_if_not_exist(account)
except Unauthorized:
return redirect(f"{dify_config.CONSOLE_WEB_URL}/signin?message=WorkspaceNotFound")
return redirect(f"{dify_config.CONSOLE_WEB_URL}/signin?message=Worspace not found.")
except WorkSpaceNotAllowedCreateError:
return redirect(
f"{dify_config.CONSOLE_WEB_URL}/signin?message=Workspace not found, please contact system admin to invite you to join in a workspace."
f"{dify_config.CONSOLE_WEB_URL}/signin"
"?message=Workspace not found, please contact system admin to invite you to join in a workspace."
)

token = AccountService.login(account, ip_address=get_remote_ip(request))
Expand Down Expand Up @@ -147,7 +149,8 @@ def _generate_account(provider: str, user_info: OAuthUserInfo):
tenant_was_created.send(tenant)

if not account:
# Create account
if not dify_config.ALLOW_REGISTER:
raise AccountNotFoundError()
account_name = user_info.name or "Dify"
account = RegisterService.register(
email=user_info.email, name=account_name, password=None, open_id=user_info.id, provider=provider
Expand Down
6 changes: 3 additions & 3 deletions api/controllers/console/datasets/datasets_document.py
Original file line number Diff line number Diff line change
Expand Up @@ -354,7 +354,7 @@ def get(self, dataset_id, document_id):
document_id = str(document_id)
document = self.get_document(dataset_id, document_id)

if document.indexing_status in ["completed", "error"]:
if document.indexing_status in {"completed", "error"}:
raise DocumentAlreadyFinishedError()

data_process_rule = document.dataset_process_rule
Expand Down Expand Up @@ -421,7 +421,7 @@ def get(self, dataset_id, batch):
info_list = []
extract_settings = []
for document in documents:
if document.indexing_status in ["completed", "error"]:
if document.indexing_status in {"completed", "error"}:
raise DocumentAlreadyFinishedError()
data_source_info = document.data_source_info_dict
# format document files info
Expand Down Expand Up @@ -665,7 +665,7 @@ def patch(self, dataset_id, document_id, action):
db.session.commit()

elif action == "resume":
if document.indexing_status not in ["paused", "error"]:
if document.indexing_status not in {"paused", "error"}:
raise InvalidActionError("Document not in paused or error state.")

document.paused_by = None
Expand Down
2 changes: 1 addition & 1 deletion api/controllers/console/explore/audio.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ def post(self, installed_app):
message_id = args.get("message_id", None)
text = args.get("text", None)
if (
app_model.mode in [AppMode.ADVANCED_CHAT.value, AppMode.WORKFLOW.value]
app_model.mode in {AppMode.ADVANCED_CHAT.value, AppMode.WORKFLOW.value}
and app_model.workflow
and app_model.workflow.features_dict
):
Expand Down
4 changes: 2 additions & 2 deletions api/controllers/console/explore/completion.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ class ChatApi(InstalledAppResource):
def post(self, installed_app):
app_model = installed_app.app
app_mode = AppMode.value_of(app_model.mode)
if app_mode not in [AppMode.CHAT, AppMode.AGENT_CHAT, AppMode.ADVANCED_CHAT]:
if app_mode not in {AppMode.CHAT, AppMode.AGENT_CHAT, AppMode.ADVANCED_CHAT}:
raise NotChatAppError()

parser = reqparse.RequestParser()
Expand Down Expand Up @@ -140,7 +140,7 @@ class ChatStopApi(InstalledAppResource):
def post(self, installed_app, task_id):
app_model = installed_app.app
app_mode = AppMode.value_of(app_model.mode)
if app_mode not in [AppMode.CHAT, AppMode.AGENT_CHAT, AppMode.ADVANCED_CHAT]:
if app_mode not in {AppMode.CHAT, AppMode.AGENT_CHAT, AppMode.ADVANCED_CHAT}:
raise NotChatAppError()

AppQueueManager.set_stop_flag(task_id, InvokeFrom.EXPLORE, current_user.id)
Expand Down
10 changes: 5 additions & 5 deletions api/controllers/console/explore/conversation.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ class ConversationListApi(InstalledAppResource):
def get(self, installed_app):
app_model = installed_app.app
app_mode = AppMode.value_of(app_model.mode)
if app_mode not in [AppMode.CHAT, AppMode.AGENT_CHAT, AppMode.ADVANCED_CHAT]:
if app_mode not in {AppMode.CHAT, AppMode.AGENT_CHAT, AppMode.ADVANCED_CHAT}:
raise NotChatAppError()

parser = reqparse.RequestParser()
Expand Down Expand Up @@ -50,7 +50,7 @@ class ConversationApi(InstalledAppResource):
def delete(self, installed_app, c_id):
app_model = installed_app.app
app_mode = AppMode.value_of(app_model.mode)
if app_mode not in [AppMode.CHAT, AppMode.AGENT_CHAT, AppMode.ADVANCED_CHAT]:
if app_mode not in {AppMode.CHAT, AppMode.AGENT_CHAT, AppMode.ADVANCED_CHAT}:
raise NotChatAppError()

conversation_id = str(c_id)
Expand All @@ -68,7 +68,7 @@ class ConversationRenameApi(InstalledAppResource):
def post(self, installed_app, c_id):
app_model = installed_app.app
app_mode = AppMode.value_of(app_model.mode)
if app_mode not in [AppMode.CHAT, AppMode.AGENT_CHAT, AppMode.ADVANCED_CHAT]:
if app_mode not in {AppMode.CHAT, AppMode.AGENT_CHAT, AppMode.ADVANCED_CHAT}:
raise NotChatAppError()

conversation_id = str(c_id)
Expand All @@ -90,7 +90,7 @@ class ConversationPinApi(InstalledAppResource):
def patch(self, installed_app, c_id):
app_model = installed_app.app
app_mode = AppMode.value_of(app_model.mode)
if app_mode not in [AppMode.CHAT, AppMode.AGENT_CHAT, AppMode.ADVANCED_CHAT]:
if app_mode not in {AppMode.CHAT, AppMode.AGENT_CHAT, AppMode.ADVANCED_CHAT}:
raise NotChatAppError()

conversation_id = str(c_id)
Expand All @@ -107,7 +107,7 @@ class ConversationUnPinApi(InstalledAppResource):
def patch(self, installed_app, c_id):
app_model = installed_app.app
app_mode = AppMode.value_of(app_model.mode)
if app_mode not in [AppMode.CHAT, AppMode.AGENT_CHAT, AppMode.ADVANCED_CHAT]:
if app_mode not in {AppMode.CHAT, AppMode.AGENT_CHAT, AppMode.ADVANCED_CHAT}:
raise NotChatAppError()

conversation_id = str(c_id)
Expand Down
2 changes: 1 addition & 1 deletion api/controllers/console/explore/installed_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ def get(self):
"app_owner_tenant_id": installed_app.app_owner_tenant_id,
"is_pinned": installed_app.is_pinned,
"last_used_at": installed_app.last_used_at,
"editable": current_user.role in ["owner", "admin"],
"editable": current_user.role in {"owner", "admin"},
"uninstallable": current_tenant_id == installed_app.app_owner_tenant_id,
}
for installed_app in installed_apps
Expand Down
4 changes: 2 additions & 2 deletions api/controllers/console/explore/message.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ def get(self, installed_app):
app_model = installed_app.app

app_mode = AppMode.value_of(app_model.mode)
if app_mode not in [AppMode.CHAT, AppMode.AGENT_CHAT, AppMode.ADVANCED_CHAT]:
if app_mode not in {AppMode.CHAT, AppMode.AGENT_CHAT, AppMode.ADVANCED_CHAT}:
raise NotChatAppError()

parser = reqparse.RequestParser()
Expand Down Expand Up @@ -125,7 +125,7 @@ class MessageSuggestedQuestionApi(InstalledAppResource):
def get(self, installed_app, message_id):
app_model = installed_app.app
app_mode = AppMode.value_of(app_model.mode)
if app_mode not in [AppMode.CHAT, AppMode.AGENT_CHAT, AppMode.ADVANCED_CHAT]:
if app_mode not in {AppMode.CHAT, AppMode.AGENT_CHAT, AppMode.ADVANCED_CHAT}:
raise NotChatAppError()

message_id = str(message_id)
Expand Down
2 changes: 1 addition & 1 deletion api/controllers/console/explore/parameter.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ def get(self, installed_app: InstalledApp):
"""Retrieve app parameters."""
app_model = installed_app.app

if app_model.mode in [AppMode.ADVANCED_CHAT.value, AppMode.WORKFLOW.value]:
if app_model.mode in {AppMode.ADVANCED_CHAT.value, AppMode.WORKFLOW.value}:
workflow = app_model.workflow
if workflow is None:
raise AppUnavailableError()
Expand Down
2 changes: 1 addition & 1 deletion api/controllers/console/workspace/workspace.py
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ def post(self):
raise TooManyFilesError()

extension = file.filename.split(".")[-1]
if extension.lower() not in ["svg", "png"]:
if extension.lower() not in {"svg", "png"}:
raise UnsupportedFileTypeError()

try:
Expand Down
2 changes: 1 addition & 1 deletion api/controllers/service_api/app/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ class AppParameterApi(Resource):
@marshal_with(parameters_fields)
def get(self, app_model: App):
"""Retrieve app parameters."""
if app_model.mode in [AppMode.ADVANCED_CHAT.value, AppMode.WORKFLOW.value]:
if app_model.mode in {AppMode.ADVANCED_CHAT.value, AppMode.WORKFLOW.value}:
workflow = app_model.workflow
if workflow is None:
raise AppUnavailableError()
Expand Down
2 changes: 1 addition & 1 deletion api/controllers/service_api/app/audio.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ def post(self, app_model: App, end_user: EndUser):
message_id = args.get("message_id", None)
text = args.get("text", None)
if (
app_model.mode in [AppMode.ADVANCED_CHAT.value, AppMode.WORKFLOW.value]
app_model.mode in {AppMode.ADVANCED_CHAT.value, AppMode.WORKFLOW.value}
and app_model.workflow
and app_model.workflow.features_dict
):
Expand Down
4 changes: 2 additions & 2 deletions api/controllers/service_api/app/completion.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ class ChatApi(Resource):
@validate_app_token(fetch_user_arg=FetchUserArg(fetch_from=WhereisUserArg.JSON, required=True))
def post(self, app_model: App, end_user: EndUser):
app_mode = AppMode.value_of(app_model.mode)
if app_mode not in [AppMode.CHAT, AppMode.AGENT_CHAT, AppMode.ADVANCED_CHAT]:
if app_mode not in {AppMode.CHAT, AppMode.AGENT_CHAT, AppMode.ADVANCED_CHAT}:
raise NotChatAppError()

parser = reqparse.RequestParser()
Expand Down Expand Up @@ -144,7 +144,7 @@ class ChatStopApi(Resource):
@validate_app_token(fetch_user_arg=FetchUserArg(fetch_from=WhereisUserArg.JSON, required=True))
def post(self, app_model: App, end_user: EndUser, task_id):
app_mode = AppMode.value_of(app_model.mode)
if app_mode not in [AppMode.CHAT, AppMode.AGENT_CHAT, AppMode.ADVANCED_CHAT]:
if app_mode not in {AppMode.CHAT, AppMode.AGENT_CHAT, AppMode.ADVANCED_CHAT}:
raise NotChatAppError()

AppQueueManager.set_stop_flag(task_id, InvokeFrom.SERVICE_API, end_user.id)
Expand Down
6 changes: 3 additions & 3 deletions api/controllers/service_api/app/conversation.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class ConversationApi(Resource):
@marshal_with(conversation_infinite_scroll_pagination_fields)
def get(self, app_model: App, end_user: EndUser):
app_mode = AppMode.value_of(app_model.mode)
if app_mode not in [AppMode.CHAT, AppMode.AGENT_CHAT, AppMode.ADVANCED_CHAT]:
if app_mode not in {AppMode.CHAT, AppMode.AGENT_CHAT, AppMode.ADVANCED_CHAT}:
raise NotChatAppError()

parser = reqparse.RequestParser()
Expand Down Expand Up @@ -52,7 +52,7 @@ class ConversationDetailApi(Resource):
@marshal_with(simple_conversation_fields)
def delete(self, app_model: App, end_user: EndUser, c_id):
app_mode = AppMode.value_of(app_model.mode)
if app_mode not in [AppMode.CHAT, AppMode.AGENT_CHAT, AppMode.ADVANCED_CHAT]:
if app_mode not in {AppMode.CHAT, AppMode.AGENT_CHAT, AppMode.ADVANCED_CHAT}:
raise NotChatAppError()

conversation_id = str(c_id)
Expand All @@ -69,7 +69,7 @@ class ConversationRenameApi(Resource):
@marshal_with(simple_conversation_fields)
def post(self, app_model: App, end_user: EndUser, c_id):
app_mode = AppMode.value_of(app_model.mode)
if app_mode not in [AppMode.CHAT, AppMode.AGENT_CHAT, AppMode.ADVANCED_CHAT]:
if app_mode not in {AppMode.CHAT, AppMode.AGENT_CHAT, AppMode.ADVANCED_CHAT}:
raise NotChatAppError()

conversation_id = str(c_id)
Expand Down
4 changes: 2 additions & 2 deletions api/controllers/service_api/app/message.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ class MessageListApi(Resource):
@marshal_with(message_infinite_scroll_pagination_fields)
def get(self, app_model: App, end_user: EndUser):
app_mode = AppMode.value_of(app_model.mode)
if app_mode not in [AppMode.CHAT, AppMode.AGENT_CHAT, AppMode.ADVANCED_CHAT]:
if app_mode not in {AppMode.CHAT, AppMode.AGENT_CHAT, AppMode.ADVANCED_CHAT}:
raise NotChatAppError()

parser = reqparse.RequestParser()
Expand Down Expand Up @@ -117,7 +117,7 @@ class MessageSuggestedApi(Resource):
def get(self, app_model: App, end_user: EndUser, message_id):
message_id = str(message_id)
app_mode = AppMode.value_of(app_model.mode)
if app_mode not in [AppMode.CHAT, AppMode.AGENT_CHAT, AppMode.ADVANCED_CHAT]:
if app_mode not in {AppMode.CHAT, AppMode.AGENT_CHAT, AppMode.ADVANCED_CHAT}:
raise NotChatAppError()

try:
Expand Down
Loading

0 comments on commit dbe759d

Please sign in to comment.