This PR refactors the handling of the default end user session ID by centralizing it as an enum in the models module where the `EndUser` model is defined. This improves code organization and makes the relationship between the constant and the model clearer. Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: crazywoola <100913391+crazywoola@users.noreply.github.com>tags/1.9.0
| @@ -86,7 +86,7 @@ class PluginUploadFileApi(Resource): | |||
| filename=filename, | |||
| mimetype=mimetype, | |||
| tenant_id=tenant_id, | |||
| user_id=user_id, | |||
| user_id=user.id, | |||
| timestamp=timestamp, | |||
| nonce=nonce, | |||
| sign=sign, | |||
| @@ -8,11 +8,10 @@ from flask_restx import reqparse | |||
| from pydantic import BaseModel | |||
| from sqlalchemy.orm import Session | |||
| from core.file.constants import DEFAULT_SERVICE_API_USER_ID | |||
| from extensions.ext_database import db | |||
| from libs.login import current_user | |||
| from models.account import Tenant | |||
| from models.model import EndUser | |||
| from models.model import DefaultEndUserSessionID, EndUser | |||
| P = ParamSpec("P") | |||
| R = TypeVar("R") | |||
| @@ -28,7 +27,7 @@ def get_user(tenant_id: str, user_id: str | None) -> EndUser: | |||
| try: | |||
| with Session(db.engine) as session: | |||
| if not user_id: | |||
| user_id = DEFAULT_SERVICE_API_USER_ID | |||
| user_id = DefaultEndUserSessionID.DEFAULT_SESSION_ID.value | |||
| user_model = ( | |||
| session.query(EndUser) | |||
| @@ -42,7 +41,7 @@ def get_user(tenant_id: str, user_id: str | None) -> EndUser: | |||
| user_model = EndUser( | |||
| tenant_id=tenant_id, | |||
| type="service_api", | |||
| is_anonymous=user_id == DEFAULT_SERVICE_API_USER_ID, | |||
| is_anonymous=user_id == DefaultEndUserSessionID.DEFAULT_SESSION_ID.value, | |||
| session_id=user_id, | |||
| ) | |||
| session.add(user_model) | |||
| @@ -73,7 +72,7 @@ def get_user_tenant(view: Optional[Callable[P, R]] = None): | |||
| raise ValueError("tenant_id is required") | |||
| if not user_id: | |||
| user_id = DEFAULT_SERVICE_API_USER_ID | |||
| user_id = DefaultEndUserSessionID.DEFAULT_SESSION_ID.value | |||
| try: | |||
| tenant_model = ( | |||
| @@ -13,14 +13,13 @@ from sqlalchemy import select, update | |||
| from sqlalchemy.orm import Session | |||
| from werkzeug.exceptions import Forbidden, NotFound, Unauthorized | |||
| from core.file.constants import DEFAULT_SERVICE_API_USER_ID | |||
| from extensions.ext_database import db | |||
| from extensions.ext_redis import redis_client | |||
| from libs.datetime_utils import naive_utc_now | |||
| from libs.login import current_user | |||
| from models.account import Account, Tenant, TenantAccountJoin, TenantStatus | |||
| from models.dataset import Dataset, RateLimitLog | |||
| from models.model import ApiToken, App, EndUser | |||
| from models.model import ApiToken, App, DefaultEndUserSessionID, EndUser | |||
| from services.feature_service import FeatureService | |||
| P = ParamSpec("P") | |||
| @@ -273,7 +272,7 @@ def create_or_update_end_user_for_user_id(app_model: App, user_id: Optional[str] | |||
| Create or update session terminal based on user ID. | |||
| """ | |||
| if not user_id: | |||
| user_id = DEFAULT_SERVICE_API_USER_ID | |||
| user_id = DefaultEndUserSessionID.DEFAULT_SESSION_ID.value | |||
| with Session(db.engine, expire_on_commit=False) as session: | |||
| end_user = ( | |||
| @@ -292,7 +291,7 @@ def create_or_update_end_user_for_user_id(app_model: App, user_id: Optional[str] | |||
| tenant_id=app_model.tenant_id, | |||
| app_id=app_model.id, | |||
| type="service_api", | |||
| is_anonymous=user_id == DEFAULT_SERVICE_API_USER_ID, | |||
| is_anonymous=user_id == DefaultEndUserSessionID.DEFAULT_SESSION_ID.value, | |||
| session_id=user_id, | |||
| ) | |||
| session.add(end_user) | |||
| @@ -9,7 +9,3 @@ FILE_MODEL_IDENTITY = "__dify__file__" | |||
| def maybe_file_object(o: Any) -> bool: | |||
| return isinstance(o, dict) and o.get("dify_model_identity") == FILE_MODEL_IDENTITY | |||
| # The default user ID for service API calls. | |||
| DEFAULT_SERVICE_API_USER_ID = "DEFAULT-USER" | |||
| @@ -5,7 +5,6 @@ import os | |||
| import time | |||
| from configs import dify_config | |||
| from core.file.constants import DEFAULT_SERVICE_API_USER_ID | |||
| def get_signed_file_url(upload_file_id: str) -> str: | |||
| @@ -25,10 +24,6 @@ def get_signed_file_url_for_plugin(filename: str, mimetype: str, tenant_id: str, | |||
| # Plugin access should use internal URL for Docker network communication | |||
| base_url = dify_config.INTERNAL_FILES_URL or dify_config.FILES_URL | |||
| url = f"{base_url}/files/upload/for-plugin" | |||
| if user_id is None: | |||
| user_id = DEFAULT_SERVICE_API_USER_ID | |||
| timestamp = str(int(time.time())) | |||
| nonce = os.urandom(16).hex() | |||
| key = dify_config.SECRET_KEY.encode() | |||
| @@ -40,11 +35,8 @@ def get_signed_file_url_for_plugin(filename: str, mimetype: str, tenant_id: str, | |||
| def verify_plugin_file_signature( | |||
| *, filename: str, mimetype: str, tenant_id: str, user_id: str | None, timestamp: str, nonce: str, sign: str | |||
| *, filename: str, mimetype: str, tenant_id: str, user_id: str, timestamp: str, nonce: str, sign: str | |||
| ) -> bool: | |||
| if user_id is None: | |||
| user_id = DEFAULT_SERVICE_API_USER_ID | |||
| data_to_sign = f"upload|{filename}|{mimetype}|{tenant_id}|{user_id}|{timestamp}|{nonce}" | |||
| secret_key = dify_config.SECRET_KEY.encode() | |||
| recalculated_sign = hmac.new(secret_key, data_to_sign.encode(), hashlib.sha256).digest() | |||
| @@ -1459,6 +1459,14 @@ class OperationLog(Base): | |||
| updated_at = mapped_column(sa.DateTime, nullable=False, server_default=func.current_timestamp()) | |||
| class DefaultEndUserSessionID(StrEnum): | |||
| """ | |||
| End User Session ID enum. | |||
| """ | |||
| DEFAULT_SESSION_ID = "DEFAULT-USER" | |||
| class EndUser(Base, UserMixin): | |||
| __tablename__ = "end_users" | |||
| __table_args__ = ( | |||