From 1bb990719e27e019fda4aa3038effc7b027a8bd7 Mon Sep 17 00:00:00 2001 From: liwenju0 Date: Fri, 21 Mar 2025 09:38:15 +0800 Subject: [PATCH] Feat: Add user registration toggle feature (#6327) ### What problem does this PR solve? Feat: Add user registration toggle feature. Added a user registration toggle REGISTER_ENABLED in the settings and .env config file. The user creation interface now checks the state of this toggle to control the enabling and disabling of the user registration feature. the front-end implementation is done, the registration button does not appear if registration is not allowed. I did the actual tests on my local server and it worked smoothly. ### Type of change - [x] New Feature (non-breaking change which adds functionality) --------- Co-authored-by: wenju.li Co-authored-by: Kevin Hu --- api/apps/system_app.py | 23 ++++++++++++++++++++++- api/apps/user_app.py | 8 ++++++++ api/settings.py | 9 ++++++++- docker/.env | 3 +++ web/src/hooks/login-hooks.ts | 2 ++ web/src/hooks/system-hooks.ts | 18 ++++++++++++++++++ web/src/locales/en.ts | 1 + web/src/pages/login/index.tsx | 8 +++++++- web/src/services/user-service.ts | 5 +++++ web/src/utils/api.ts | 1 + 10 files changed, 75 insertions(+), 3 deletions(-) create mode 100644 web/src/hooks/system-hooks.ts diff --git a/api/apps/system_app.py b/api/apps/system_app.py index c1ae5ec3b4..c4a70bcacb 100644 --- a/api/apps/system_app.py +++ b/api/apps/system_app.py @@ -37,7 +37,6 @@ from timeit import default_timer as timer from rag.utils.redis_conn import REDIS_CONN - @manager.route("/version", methods=["GET"]) # noqa: F821 @login_required def version(): @@ -298,3 +297,25 @@ def rm(token): [APIToken.tenant_id == current_user.id, APIToken.token == token] ) return get_json_result(data=True) + + +@manager.route('/config', methods=['GET']) # noqa: F821 +def get_config(): + """ + Get system configuration. + --- + tags: + - System + responses: + 200: + description: Return system configuration + schema: + type: object + properties: + registerEnable: + type: integer 0 means disabled, 1 means enabled + description: Whether user registration is enabled + """ + return get_json_result(data={ + "registerEnabled": settings.REGISTER_ENABLED + }) diff --git a/api/apps/user_app.py b/api/apps/user_app.py index 1cf85986c8..89e7714482 100644 --- a/api/apps/user_app.py +++ b/api/apps/user_app.py @@ -562,6 +562,14 @@ def user_add(): schema: type: object """ + + if not settings.REGISTER_ENABLED: + return get_json_result( + data=False, + message="User registration is disabled!", + code=settings.RetCode.OPERATING_ERROR, + ) + req = request.json email_address = req["email"] diff --git a/api/settings.py b/api/settings.py index d4b829cf90..87b4858b99 100644 --- a/api/settings.py +++ b/api/settings.py @@ -62,9 +62,12 @@ docStoreConn = None retrievaler = None kg_retrievaler = None +# user registration switch +REGISTER_ENABLED = 1 + def init_settings(): - global LLM, LLM_FACTORY, LLM_BASE_URL, LIGHTEN, DATABASE_TYPE, DATABASE, FACTORY_LLM_INFOS + global LLM, LLM_FACTORY, LLM_BASE_URL, LIGHTEN, DATABASE_TYPE, DATABASE, FACTORY_LLM_INFOS, REGISTER_ENABLED LIGHTEN = int(os.environ.get('LIGHTEN', "0")) DATABASE_TYPE = os.getenv("DB_TYPE", 'mysql') DATABASE = decrypt_database_config(name=DATABASE_TYPE) @@ -72,6 +75,10 @@ def init_settings(): LLM_DEFAULT_MODELS = LLM.get("default_models", {}) LLM_FACTORY = LLM.get("factory", "Tongyi-Qianwen") LLM_BASE_URL = LLM.get("base_url") + try: + REGISTER_ENABLED = int(os.environ.get("REGISTER_ENABLED", "1")) + except Exception: + pass try: with open(os.path.join(get_project_base_directory(), "conf", "llm_factories.json"), "r") as f: diff --git a/docker/.env b/docker/.env index 2b0b5b8be9..40a8a3c5ec 100644 --- a/docker/.env +++ b/docker/.env @@ -146,3 +146,6 @@ TIMEZONE='Asia/Shanghai' # ENDPOINT=http://oss-cn-hangzhou.aliyuncs.com # REGION=cn-hangzhou # BUCKET=ragflow65536 + +# user registration switch +REGISTER_ENABLED=1 diff --git a/web/src/hooks/login-hooks.ts b/web/src/hooks/login-hooks.ts index 8f8c292c35..ddecc3ce7d 100644 --- a/web/src/hooks/login-hooks.ts +++ b/web/src/hooks/login-hooks.ts @@ -67,6 +67,8 @@ export const useRegister = () => { const { data = {} } = await userService.register(params); if (data.code === 0) { message.success(t('message.registered')); + } else if (data.message && data.message.includes('registration is disabled')) { + message.error(t('message.registerDisabled') || 'User registration is disabled'); } return data.code; }, diff --git a/web/src/hooks/system-hooks.ts b/web/src/hooks/system-hooks.ts new file mode 100644 index 0000000000..b5ce929694 --- /dev/null +++ b/web/src/hooks/system-hooks.ts @@ -0,0 +1,18 @@ +import userService from '@/services/user-service'; +import { useQuery } from '@tanstack/react-query'; + +/** + * Hook to fetch system configuration including register enable status + * @returns System configuration with loading status + */ +export const useSystemConfig = () => { + const { data, isLoading } = useQuery({ + queryKey: ['systemConfig'], + queryFn: async () => { + const { data = {} } = await userService.getSystemConfig(); + return data.data || { registerEnabled: 1 }; // Default to enabling registration + }, + }); + + return { config: data, loading: isLoading }; +}; diff --git a/web/src/locales/en.ts b/web/src/locales/en.ts index c686e03a34..181bbcf345 100644 --- a/web/src/locales/en.ts +++ b/web/src/locales/en.ts @@ -705,6 +705,7 @@ This auto-tag feature enhances retrieval by adding another layer of domain-speci logout: 'logout', logged: 'logged!', pleaseSelectChunk: 'Please select chunk!', + registerDisabled: 'User registration is disabled', modified: 'Modified', created: 'Created', deleted: 'Deleted', diff --git a/web/src/pages/login/index.tsx b/web/src/pages/login/index.tsx index 0bc24cf047..dab0b264c9 100644 --- a/web/src/pages/login/index.tsx +++ b/web/src/pages/login/index.tsx @@ -1,4 +1,5 @@ import { useLogin, useRegister } from '@/hooks/login-hooks'; +import { useSystemConfig } from '@/hooks/system-hooks'; import { rsaPsw } from '@/utils'; import { Button, Checkbox, Form, Input } from 'antd'; import { useEffect, useState } from 'react'; @@ -16,8 +17,13 @@ const Login = () => { const { register, loading: registerLoading } = useRegister(); const { t } = useTranslation('translation', { keyPrefix: 'login' }); const loading = signLoading || registerLoading; + const { config } = useSystemConfig(); + const registerEnabled = config?.registerEnabled !== 0; const changeTitle = () => { + if (title === 'login' && !registerEnabled) { + return; + } setTitle((title) => (title === 'login' ? 'register' : 'login')); }; const [form] = Form.useForm(); @@ -119,7 +125,7 @@ const Login = () => { )}
- {title === 'login' && ( + {title === 'login' && registerEnabled && (
{t('signInTip')}