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
| filename=filename, | filename=filename, | ||||
| mimetype=mimetype, | mimetype=mimetype, | ||||
| tenant_id=tenant_id, | tenant_id=tenant_id, | ||||
| user_id=user_id, | |||||
| user_id=user.id, | |||||
| timestamp=timestamp, | timestamp=timestamp, | ||||
| nonce=nonce, | nonce=nonce, | ||||
| sign=sign, | sign=sign, |
| from pydantic import BaseModel | from pydantic import BaseModel | ||||
| from sqlalchemy.orm import Session | from sqlalchemy.orm import Session | ||||
| from core.file.constants import DEFAULT_SERVICE_API_USER_ID | |||||
| from extensions.ext_database import db | from extensions.ext_database import db | ||||
| from libs.login import current_user | from libs.login import current_user | ||||
| from models.account import Tenant | from models.account import Tenant | ||||
| from models.model import EndUser | |||||
| from models.model import DefaultEndUserSessionID, EndUser | |||||
| P = ParamSpec("P") | P = ParamSpec("P") | ||||
| R = TypeVar("R") | R = TypeVar("R") | ||||
| try: | try: | ||||
| with Session(db.engine) as session: | with Session(db.engine) as session: | ||||
| if not user_id: | if not user_id: | ||||
| user_id = DEFAULT_SERVICE_API_USER_ID | |||||
| user_id = DefaultEndUserSessionID.DEFAULT_SESSION_ID.value | |||||
| user_model = ( | user_model = ( | ||||
| session.query(EndUser) | session.query(EndUser) | ||||
| user_model = EndUser( | user_model = EndUser( | ||||
| tenant_id=tenant_id, | tenant_id=tenant_id, | ||||
| type="service_api", | 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_id=user_id, | ||||
| ) | ) | ||||
| session.add(user_model) | session.add(user_model) | ||||
| raise ValueError("tenant_id is required") | raise ValueError("tenant_id is required") | ||||
| if not user_id: | if not user_id: | ||||
| user_id = DEFAULT_SERVICE_API_USER_ID | |||||
| user_id = DefaultEndUserSessionID.DEFAULT_SESSION_ID.value | |||||
| try: | try: | ||||
| tenant_model = ( | tenant_model = ( |
| from sqlalchemy.orm import Session | from sqlalchemy.orm import Session | ||||
| from werkzeug.exceptions import Forbidden, NotFound, Unauthorized | 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_database import db | ||||
| from extensions.ext_redis import redis_client | from extensions.ext_redis import redis_client | ||||
| from libs.datetime_utils import naive_utc_now | from libs.datetime_utils import naive_utc_now | ||||
| from libs.login import current_user | from libs.login import current_user | ||||
| from models.account import Account, Tenant, TenantAccountJoin, TenantStatus | from models.account import Account, Tenant, TenantAccountJoin, TenantStatus | ||||
| from models.dataset import Dataset, RateLimitLog | 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 | from services.feature_service import FeatureService | ||||
| P = ParamSpec("P") | P = ParamSpec("P") | ||||
| Create or update session terminal based on user ID. | Create or update session terminal based on user ID. | ||||
| """ | """ | ||||
| if not 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: | with Session(db.engine, expire_on_commit=False) as session: | ||||
| end_user = ( | end_user = ( | ||||
| tenant_id=app_model.tenant_id, | tenant_id=app_model.tenant_id, | ||||
| app_id=app_model.id, | app_id=app_model.id, | ||||
| type="service_api", | 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_id=user_id, | ||||
| ) | ) | ||||
| session.add(end_user) | session.add(end_user) |
| def maybe_file_object(o: Any) -> bool: | def maybe_file_object(o: Any) -> bool: | ||||
| return isinstance(o, dict) and o.get("dify_model_identity") == FILE_MODEL_IDENTITY | 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" |
| import time | import time | ||||
| from configs import dify_config | 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: | def get_signed_file_url(upload_file_id: str) -> str: | ||||
| # Plugin access should use internal URL for Docker network communication | # Plugin access should use internal URL for Docker network communication | ||||
| base_url = dify_config.INTERNAL_FILES_URL or dify_config.FILES_URL | base_url = dify_config.INTERNAL_FILES_URL or dify_config.FILES_URL | ||||
| url = f"{base_url}/files/upload/for-plugin" | 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())) | timestamp = str(int(time.time())) | ||||
| nonce = os.urandom(16).hex() | nonce = os.urandom(16).hex() | ||||
| key = dify_config.SECRET_KEY.encode() | key = dify_config.SECRET_KEY.encode() | ||||
| def verify_plugin_file_signature( | 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: | ) -> 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}" | data_to_sign = f"upload|{filename}|{mimetype}|{tenant_id}|{user_id}|{timestamp}|{nonce}" | ||||
| secret_key = dify_config.SECRET_KEY.encode() | secret_key = dify_config.SECRET_KEY.encode() | ||||
| recalculated_sign = hmac.new(secret_key, data_to_sign.encode(), hashlib.sha256).digest() | recalculated_sign = hmac.new(secret_key, data_to_sign.encode(), hashlib.sha256).digest() |
| updated_at = mapped_column(sa.DateTime, nullable=False, server_default=func.current_timestamp()) | 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): | class EndUser(Base, UserMixin): | ||||
| __tablename__ = "end_users" | __tablename__ = "end_users" | ||||
| __table_args__ = ( | __table_args__ = ( |