mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-07-06 22:12:12 +02:00
refactor(db): rename SearchSpace ORM core to Workspace (Phase 2 Wave A)
Flip the symbolic name in db.py: classes SearchSpace/Role/Membership/Invite ->
Workspace*, attributes search_space_id -> workspace_id (and owner_*), relationship
attrs + back_populates pairs, and drop the Phase 1 Column("workspace_id", ...) shim
now that attribute name == column name. Enum values 'SEARCH_SPACE' and the
SearchSourceConnector class are intentionally untouched (carve-outs).
Part of the atomic SearchSpace -> Workspace rename; the suite goes green only once
Waves B-F land (no half-renamed steady state).
This commit is contained in:
parent
49d3001fbf
commit
df03565940
1 changed files with 97 additions and 117 deletions
|
|
@ -292,7 +292,7 @@ INCENTIVE_TASKS_CONFIG = {
|
|||
|
||||
class Permission(StrEnum):
|
||||
"""
|
||||
Granular permissions for search space resources.
|
||||
Granular permissions for workspace resources.
|
||||
Use '*' (FULL_ACCESS) to grant all permissions.
|
||||
"""
|
||||
|
||||
|
|
@ -363,10 +363,10 @@ class Permission(StrEnum):
|
|||
ROLES_UPDATE = "roles:update"
|
||||
ROLES_DELETE = "roles:delete"
|
||||
|
||||
# Search Space Settings
|
||||
# Workspace Settings
|
||||
SETTINGS_VIEW = "settings:view"
|
||||
SETTINGS_UPDATE = "settings:update"
|
||||
SETTINGS_DELETE = "settings:delete" # Delete the entire search space
|
||||
SETTINGS_DELETE = "settings:delete" # Delete the entire workspace
|
||||
|
||||
# API Access
|
||||
API_ACCESS_MANAGE = "api_access:manage"
|
||||
|
|
@ -515,7 +515,7 @@ class ChatVisibility(StrEnum):
|
|||
Visibility/sharing level for chat threads.
|
||||
|
||||
PRIVATE: Only the creator can see/access the chat (default)
|
||||
SEARCH_SPACE: All members of the search space can see/access the chat
|
||||
SEARCH_SPACE: All members of the workspace can see/access the chat
|
||||
PUBLIC: (Future) Anyone with the link can access the chat
|
||||
"""
|
||||
|
||||
|
|
@ -605,8 +605,7 @@ class NewChatThread(BaseModel, TimestampMixin):
|
|||
)
|
||||
|
||||
# Foreign keys
|
||||
search_space_id = Column(
|
||||
"workspace_id",
|
||||
workspace_id = Column(
|
||||
Integer,
|
||||
ForeignKey("workspaces.id", ondelete="CASCADE"),
|
||||
nullable=False,
|
||||
|
|
@ -647,7 +646,7 @@ class NewChatThread(BaseModel, TimestampMixin):
|
|||
# Auto model pin for this thread: concrete resolved global LLM
|
||||
# config id. NULL means no pin; Auto will resolve on the next turn.
|
||||
# Single-writer invariant: only app.services.auto_model_pin_service sets
|
||||
# or clears this column (plus bulk clears when a search space's
|
||||
# or clears this column (plus bulk clears when a workspace's
|
||||
# chat_model_id changes). Unindexed: all reads are by primary key.
|
||||
pinned_llm_config_id = Column(Integer, nullable=True)
|
||||
|
||||
|
|
@ -664,7 +663,7 @@ class NewChatThread(BaseModel, TimestampMixin):
|
|||
)
|
||||
|
||||
# Relationships
|
||||
search_space = relationship("SearchSpace", back_populates="new_chat_threads")
|
||||
workspace = relationship("Workspace", back_populates="new_chat_threads")
|
||||
created_by = relationship("User", back_populates="new_chat_threads")
|
||||
messages = relationship(
|
||||
"NewChatMessage",
|
||||
|
|
@ -788,8 +787,7 @@ class ExternalChatAccount(Base, TimestampMixin):
|
|||
owner_user_id = Column(
|
||||
UUID(as_uuid=True), ForeignKey("user.id", ondelete="CASCADE"), nullable=True
|
||||
)
|
||||
owner_search_space_id = Column(
|
||||
"owner_workspace_id",
|
||||
owner_workspace_id = Column(
|
||||
Integer,
|
||||
ForeignKey("workspaces.id", ondelete="CASCADE"),
|
||||
nullable=True,
|
||||
|
|
@ -825,8 +823,8 @@ class ExternalChatAccount(Base, TimestampMixin):
|
|||
)
|
||||
|
||||
owner = relationship("User", foreign_keys=[owner_user_id])
|
||||
owner_search_space = relationship(
|
||||
"SearchSpace", foreign_keys=[owner_search_space_id]
|
||||
owner_workspace = relationship(
|
||||
"Workspace", foreign_keys=[owner_workspace_id]
|
||||
)
|
||||
bindings = relationship(
|
||||
"ExternalChatBinding",
|
||||
|
|
@ -903,8 +901,7 @@ class ExternalChatBinding(Base, TimestampMixin):
|
|||
user_id = Column(
|
||||
UUID(as_uuid=True), ForeignKey("user.id", ondelete="CASCADE"), nullable=False
|
||||
)
|
||||
search_space_id = Column(
|
||||
"workspace_id",
|
||||
workspace_id = Column(
|
||||
Integer,
|
||||
ForeignKey("workspaces.id", ondelete="CASCADE"),
|
||||
nullable=False,
|
||||
|
|
@ -957,7 +954,7 @@ class ExternalChatBinding(Base, TimestampMixin):
|
|||
|
||||
account = relationship("ExternalChatAccount", back_populates="bindings")
|
||||
user = relationship("User", foreign_keys=[user_id])
|
||||
search_space = relationship("SearchSpace", foreign_keys=[search_space_id])
|
||||
workspace = relationship("Workspace", foreign_keys=[workspace_id])
|
||||
new_chat_thread = relationship("NewChatThread", foreign_keys=[new_chat_thread_id])
|
||||
threads = relationship(
|
||||
"NewChatThread",
|
||||
|
|
@ -1122,8 +1119,7 @@ class TokenUsage(BaseModel, TimestampMixin):
|
|||
nullable=True,
|
||||
index=True,
|
||||
)
|
||||
search_space_id = Column(
|
||||
"workspace_id",
|
||||
workspace_id = Column(
|
||||
Integer,
|
||||
ForeignKey("workspaces.id", ondelete="CASCADE"),
|
||||
nullable=False,
|
||||
|
|
@ -1139,7 +1135,7 @@ class TokenUsage(BaseModel, TimestampMixin):
|
|||
# Relationships
|
||||
thread = relationship("NewChatThread", back_populates="token_usages")
|
||||
message = relationship("NewChatMessage", back_populates="token_usage")
|
||||
search_space = relationship("SearchSpace")
|
||||
workspace = relationship("Workspace")
|
||||
user = relationship("User")
|
||||
|
||||
|
||||
|
|
@ -1328,8 +1324,7 @@ class Folder(BaseModel, TimestampMixin):
|
|||
nullable=True,
|
||||
index=True,
|
||||
)
|
||||
search_space_id = Column(
|
||||
"workspace_id",
|
||||
workspace_id = Column(
|
||||
Integer,
|
||||
ForeignKey("workspaces.id", ondelete="CASCADE"),
|
||||
nullable=False,
|
||||
|
|
@ -1351,7 +1346,7 @@ class Folder(BaseModel, TimestampMixin):
|
|||
folder_metadata = Column("metadata", JSONB, nullable=True)
|
||||
|
||||
parent = relationship("Folder", remote_side="Folder.id", backref="children")
|
||||
search_space = relationship("SearchSpace", back_populates="folders")
|
||||
workspace = relationship("Workspace", back_populates="folders")
|
||||
created_by = relationship("User", back_populates="folders")
|
||||
documents = relationship("Document", back_populates="folder", passive_deletes=True)
|
||||
|
||||
|
|
@ -1368,7 +1363,7 @@ class Document(BaseModel, TimestampMixin):
|
|||
# filesystem two files at different paths can hold identical bytes,
|
||||
# and the agent's ``write_file`` flow needs that semantic to support
|
||||
# copy / duplicate operations. Path uniqueness lives on
|
||||
# ``unique_identifier_hash`` (per search space). The hash remains
|
||||
# ``unique_identifier_hash`` (per workspace). The hash remains
|
||||
# indexed because connector indexers consult it as a change-detection
|
||||
# / cross-source dedup hint via :func:`check_duplicate_document`.
|
||||
# See migration 133.
|
||||
|
|
@ -1393,8 +1388,7 @@ class Document(BaseModel, TimestampMixin):
|
|||
# Track when document was last updated by indexers, processors, or editor
|
||||
updated_at = Column(TIMESTAMP(timezone=True), nullable=True, index=True)
|
||||
|
||||
search_space_id = Column(
|
||||
"workspace_id",
|
||||
workspace_id = Column(
|
||||
Integer,
|
||||
ForeignKey("workspaces.id", ondelete="CASCADE"),
|
||||
nullable=False,
|
||||
|
|
@ -1435,7 +1429,7 @@ class Document(BaseModel, TimestampMixin):
|
|||
)
|
||||
|
||||
# Relationships
|
||||
search_space = relationship("SearchSpace", back_populates="documents")
|
||||
workspace = relationship("Workspace", back_populates="documents")
|
||||
folder = relationship("Folder", back_populates="documents")
|
||||
created_by = relationship("User", back_populates="documents")
|
||||
connector = relationship("SearchSourceConnector", back_populates="documents")
|
||||
|
|
@ -1520,13 +1514,12 @@ class VideoPresentation(BaseModel, TimestampMixin):
|
|||
index=True,
|
||||
)
|
||||
|
||||
search_space_id = Column(
|
||||
"workspace_id",
|
||||
workspace_id = Column(
|
||||
Integer,
|
||||
ForeignKey("workspaces.id", ondelete="CASCADE"),
|
||||
nullable=False,
|
||||
)
|
||||
search_space = relationship("SearchSpace", back_populates="video_presentations")
|
||||
workspace = relationship("Workspace", back_populates="video_presentations")
|
||||
|
||||
thread_id = Column(
|
||||
Integer,
|
||||
|
|
@ -1550,13 +1543,12 @@ class Report(BaseModel, TimestampMixin):
|
|||
String(100), nullable=True
|
||||
) # e.g. "executive_summary", "deep_research"
|
||||
|
||||
search_space_id = Column(
|
||||
"workspace_id",
|
||||
workspace_id = Column(
|
||||
Integer,
|
||||
ForeignKey("workspaces.id", ondelete="CASCADE"),
|
||||
nullable=False,
|
||||
)
|
||||
search_space = relationship("SearchSpace", back_populates="reports")
|
||||
workspace = relationship("Workspace", back_populates="reports")
|
||||
|
||||
# Versioning: reports sharing the same report_group_id are versions of the same report.
|
||||
# For v1, report_group_id = the report's own id (set after insert).
|
||||
|
|
@ -1581,8 +1573,7 @@ class Connection(BaseModel, TimestampMixin):
|
|||
scope = Column(SQLAlchemyEnum(ConnectionScope), nullable=False, index=True)
|
||||
enabled = Column(Boolean, nullable=False, default=True, server_default="true")
|
||||
|
||||
search_space_id = Column(
|
||||
"workspace_id",
|
||||
workspace_id = Column(
|
||||
Integer,
|
||||
ForeignKey("workspaces.id", ondelete="CASCADE"),
|
||||
nullable=True,
|
||||
|
|
@ -1591,7 +1582,7 @@ class Connection(BaseModel, TimestampMixin):
|
|||
UUID(as_uuid=True), ForeignKey("user.id", ondelete="CASCADE"), nullable=True
|
||||
)
|
||||
|
||||
search_space = relationship("SearchSpace", back_populates="connections")
|
||||
workspace = relationship("Workspace", back_populates="connections")
|
||||
user = relationship("User", back_populates="connections")
|
||||
models = relationship(
|
||||
"Model",
|
||||
|
|
@ -1695,8 +1686,7 @@ class ImageGeneration(BaseModel, TimestampMixin):
|
|||
access_token = Column(String(64), nullable=True, index=True)
|
||||
|
||||
# Foreign keys
|
||||
search_space_id = Column(
|
||||
"workspace_id",
|
||||
workspace_id = Column(
|
||||
Integer,
|
||||
ForeignKey("workspaces.id", ondelete="CASCADE"),
|
||||
nullable=False,
|
||||
|
|
@ -1709,11 +1699,11 @@ class ImageGeneration(BaseModel, TimestampMixin):
|
|||
)
|
||||
|
||||
# Relationships
|
||||
search_space = relationship("SearchSpace", back_populates="image_generations")
|
||||
workspace = relationship("Workspace", back_populates="image_generations")
|
||||
created_by = relationship("User", back_populates="image_generations")
|
||||
|
||||
|
||||
class SearchSpace(BaseModel, TimestampMixin):
|
||||
class Workspace(BaseModel, TimestampMixin):
|
||||
__tablename__ = "workspaces"
|
||||
|
||||
name = Column(String(100), nullable=False, index=True)
|
||||
|
|
@ -1735,7 +1725,7 @@ class SearchSpace(BaseModel, TimestampMixin):
|
|||
# Note: ID values preserve the existing convention:
|
||||
# - 0: Auto mode
|
||||
# - Negative IDs: Global virtual models from global_llm_config.yaml
|
||||
# - Positive IDs: User/search-space models from the models table
|
||||
# - Positive IDs: User/workspace models from the models table
|
||||
chat_model_id = Column(
|
||||
Integer, nullable=True, default=0, server_default="0"
|
||||
) # For agent/chat operations, defaults to Auto mode
|
||||
|
|
@ -1753,71 +1743,71 @@ class SearchSpace(BaseModel, TimestampMixin):
|
|||
user_id = Column(
|
||||
UUID(as_uuid=True), ForeignKey("user.id", ondelete="CASCADE"), nullable=False
|
||||
)
|
||||
user = relationship("User", back_populates="search_spaces")
|
||||
user = relationship("User", back_populates="workspaces")
|
||||
|
||||
folders = relationship(
|
||||
"Folder",
|
||||
back_populates="search_space",
|
||||
back_populates="workspace",
|
||||
order_by="Folder.position",
|
||||
cascade="all, delete-orphan",
|
||||
)
|
||||
documents = relationship(
|
||||
"Document",
|
||||
back_populates="search_space",
|
||||
back_populates="workspace",
|
||||
order_by="Document.id",
|
||||
cascade="all, delete-orphan",
|
||||
)
|
||||
new_chat_threads = relationship(
|
||||
"NewChatThread",
|
||||
back_populates="search_space",
|
||||
back_populates="workspace",
|
||||
order_by="NewChatThread.updated_at.desc()",
|
||||
cascade="all, delete-orphan",
|
||||
)
|
||||
podcasts = relationship(
|
||||
"Podcast",
|
||||
back_populates="search_space",
|
||||
back_populates="workspace",
|
||||
order_by="Podcast.id.desc()",
|
||||
cascade="all, delete-orphan",
|
||||
)
|
||||
video_presentations = relationship(
|
||||
"VideoPresentation",
|
||||
back_populates="search_space",
|
||||
back_populates="workspace",
|
||||
order_by="VideoPresentation.id.desc()",
|
||||
cascade="all, delete-orphan",
|
||||
)
|
||||
reports = relationship(
|
||||
"Report",
|
||||
back_populates="search_space",
|
||||
back_populates="workspace",
|
||||
order_by="Report.id.desc()",
|
||||
cascade="all, delete-orphan",
|
||||
)
|
||||
image_generations = relationship(
|
||||
"ImageGeneration",
|
||||
back_populates="search_space",
|
||||
back_populates="workspace",
|
||||
order_by="ImageGeneration.id.desc()",
|
||||
cascade="all, delete-orphan",
|
||||
)
|
||||
logs = relationship(
|
||||
"Log",
|
||||
back_populates="search_space",
|
||||
back_populates="workspace",
|
||||
order_by="Log.id",
|
||||
cascade="all, delete-orphan",
|
||||
)
|
||||
notifications = relationship(
|
||||
"Notification",
|
||||
back_populates="search_space",
|
||||
back_populates="workspace",
|
||||
order_by="Notification.created_at.desc()",
|
||||
cascade="all, delete-orphan",
|
||||
)
|
||||
search_source_connectors = relationship(
|
||||
"SearchSourceConnector",
|
||||
back_populates="search_space",
|
||||
back_populates="workspace",
|
||||
order_by="SearchSourceConnector.id",
|
||||
cascade="all, delete-orphan",
|
||||
)
|
||||
connections = relationship(
|
||||
"Connection",
|
||||
back_populates="search_space",
|
||||
back_populates="workspace",
|
||||
order_by="Connection.id",
|
||||
cascade="all, delete-orphan",
|
||||
passive_deletes=True,
|
||||
|
|
@ -1825,7 +1815,7 @@ class SearchSpace(BaseModel, TimestampMixin):
|
|||
|
||||
automations = relationship(
|
||||
"Automation",
|
||||
back_populates="search_space",
|
||||
back_populates="workspace",
|
||||
order_by="Automation.id",
|
||||
cascade="all, delete-orphan",
|
||||
passive_deletes=True,
|
||||
|
|
@ -1833,21 +1823,21 @@ class SearchSpace(BaseModel, TimestampMixin):
|
|||
|
||||
# RBAC relationships
|
||||
roles = relationship(
|
||||
"SearchSpaceRole",
|
||||
back_populates="search_space",
|
||||
order_by="SearchSpaceRole.id",
|
||||
"WorkspaceRole",
|
||||
back_populates="workspace",
|
||||
order_by="WorkspaceRole.id",
|
||||
cascade="all, delete-orphan",
|
||||
)
|
||||
memberships = relationship(
|
||||
"SearchSpaceMembership",
|
||||
back_populates="search_space",
|
||||
order_by="SearchSpaceMembership.id",
|
||||
"WorkspaceMembership",
|
||||
back_populates="workspace",
|
||||
order_by="WorkspaceMembership.id",
|
||||
cascade="all, delete-orphan",
|
||||
)
|
||||
invites = relationship(
|
||||
"SearchSpaceInvite",
|
||||
back_populates="search_space",
|
||||
order_by="SearchSpaceInvite.id",
|
||||
"WorkspaceInvite",
|
||||
back_populates="workspace",
|
||||
order_by="WorkspaceInvite.id",
|
||||
cascade="all, delete-orphan",
|
||||
)
|
||||
|
||||
|
|
@ -1907,14 +1897,13 @@ class SearchSourceConnector(BaseModel, TimestampMixin):
|
|||
indexing_frequency_minutes = Column(Integer, nullable=True)
|
||||
next_scheduled_at = Column(TIMESTAMP(timezone=True), nullable=True)
|
||||
|
||||
search_space_id = Column(
|
||||
"workspace_id",
|
||||
workspace_id = Column(
|
||||
Integer,
|
||||
ForeignKey("workspaces.id", ondelete="CASCADE"),
|
||||
nullable=False,
|
||||
)
|
||||
search_space = relationship(
|
||||
"SearchSpace", back_populates="search_source_connectors"
|
||||
workspace = relationship(
|
||||
"Workspace", back_populates="search_source_connectors"
|
||||
)
|
||||
|
||||
user_id = Column(
|
||||
|
|
@ -1937,13 +1926,12 @@ class Log(BaseModel, TimestampMixin):
|
|||
) # Service/component that generated the log
|
||||
log_metadata = Column(JSON, nullable=True, default={}) # Additional context data
|
||||
|
||||
search_space_id = Column(
|
||||
"workspace_id",
|
||||
workspace_id = Column(
|
||||
Integer,
|
||||
ForeignKey("workspaces.id", ondelete="CASCADE"),
|
||||
nullable=False,
|
||||
)
|
||||
search_space = relationship("SearchSpace", back_populates="logs")
|
||||
workspace = relationship("Workspace", back_populates="logs")
|
||||
|
||||
|
||||
class UserIncentiveTask(BaseModel, TimestampMixin):
|
||||
|
|
@ -2056,10 +2044,10 @@ class CreditPurchase(Base, TimestampMixin):
|
|||
user = relationship("User", back_populates="credit_purchases")
|
||||
|
||||
|
||||
class SearchSpaceRole(BaseModel, TimestampMixin):
|
||||
class WorkspaceRole(BaseModel, TimestampMixin):
|
||||
"""
|
||||
Custom roles that can be defined per search space.
|
||||
Each search space can have multiple roles with different permission sets.
|
||||
Custom roles that can be defined per workspace.
|
||||
Each workspace can have multiple roles with different permission sets.
|
||||
"""
|
||||
|
||||
__tablename__ = "workspace_roles"
|
||||
|
|
@ -2080,26 +2068,25 @@ class SearchSpaceRole(BaseModel, TimestampMixin):
|
|||
# System roles (Owner, Editor, Viewer) cannot be deleted
|
||||
is_system_role = Column(Boolean, nullable=False, default=False)
|
||||
|
||||
search_space_id = Column(
|
||||
"workspace_id",
|
||||
workspace_id = Column(
|
||||
Integer,
|
||||
ForeignKey("workspaces.id", ondelete="CASCADE"),
|
||||
nullable=False,
|
||||
)
|
||||
search_space = relationship("SearchSpace", back_populates="roles")
|
||||
workspace = relationship("Workspace", back_populates="roles")
|
||||
|
||||
memberships = relationship(
|
||||
"SearchSpaceMembership", back_populates="role", passive_deletes=True
|
||||
"WorkspaceMembership", back_populates="role", passive_deletes=True
|
||||
)
|
||||
invites = relationship(
|
||||
"SearchSpaceInvite", back_populates="role", passive_deletes=True
|
||||
"WorkspaceInvite", back_populates="role", passive_deletes=True
|
||||
)
|
||||
|
||||
|
||||
class SearchSpaceMembership(BaseModel, TimestampMixin):
|
||||
class WorkspaceMembership(BaseModel, TimestampMixin):
|
||||
"""
|
||||
Tracks user membership in search spaces with their assigned role.
|
||||
Each user can be a member of multiple search spaces with different roles.
|
||||
Tracks user membership in workspaces with their assigned role.
|
||||
Each user can be a member of multiple workspaces with different roles.
|
||||
"""
|
||||
|
||||
__tablename__ = "workspace_memberships"
|
||||
|
|
@ -2114,8 +2101,7 @@ class SearchSpaceMembership(BaseModel, TimestampMixin):
|
|||
user_id = Column(
|
||||
UUID(as_uuid=True), ForeignKey("user.id", ondelete="CASCADE"), nullable=False
|
||||
)
|
||||
search_space_id = Column(
|
||||
"workspace_id",
|
||||
workspace_id = Column(
|
||||
Integer,
|
||||
ForeignKey("workspaces.id", ondelete="CASCADE"),
|
||||
nullable=False,
|
||||
|
|
@ -2125,7 +2111,7 @@ class SearchSpaceMembership(BaseModel, TimestampMixin):
|
|||
ForeignKey("workspace_roles.id", ondelete="SET NULL"),
|
||||
nullable=True,
|
||||
)
|
||||
# Indicates if this user is the original creator/owner of the search space
|
||||
# Indicates if this user is the original creator/owner of the workspace
|
||||
is_owner = Column(Boolean, nullable=False, default=False)
|
||||
# Timestamp when the user joined (via invite or as creator)
|
||||
joined_at = Column(
|
||||
|
|
@ -2140,17 +2126,17 @@ class SearchSpaceMembership(BaseModel, TimestampMixin):
|
|||
nullable=True,
|
||||
)
|
||||
|
||||
user = relationship("User", back_populates="search_space_memberships")
|
||||
search_space = relationship("SearchSpace", back_populates="memberships")
|
||||
role = relationship("SearchSpaceRole", back_populates="memberships")
|
||||
user = relationship("User", back_populates="workspace_memberships")
|
||||
workspace = relationship("Workspace", back_populates="memberships")
|
||||
role = relationship("WorkspaceRole", back_populates="memberships")
|
||||
invited_by_invite = relationship(
|
||||
"SearchSpaceInvite", back_populates="used_by_memberships"
|
||||
"WorkspaceInvite", back_populates="used_by_memberships"
|
||||
)
|
||||
|
||||
|
||||
class SearchSpaceInvite(BaseModel, TimestampMixin):
|
||||
class WorkspaceInvite(BaseModel, TimestampMixin):
|
||||
"""
|
||||
Invite links for search spaces.
|
||||
Invite links for workspaces.
|
||||
Users can create invite links with specific roles that others can use to join.
|
||||
"""
|
||||
|
||||
|
|
@ -2159,8 +2145,7 @@ class SearchSpaceInvite(BaseModel, TimestampMixin):
|
|||
# Unique invite code (used in invite URLs)
|
||||
invite_code = Column(String(64), nullable=False, unique=True, index=True)
|
||||
|
||||
search_space_id = Column(
|
||||
"workspace_id",
|
||||
workspace_id = Column(
|
||||
Integer,
|
||||
ForeignKey("workspaces.id", ondelete="CASCADE"),
|
||||
nullable=False,
|
||||
|
|
@ -2189,11 +2174,11 @@ class SearchSpaceInvite(BaseModel, TimestampMixin):
|
|||
# Optional custom name/label for the invite
|
||||
name = Column(String(100), nullable=True)
|
||||
|
||||
search_space = relationship("SearchSpace", back_populates="invites")
|
||||
role = relationship("SearchSpaceRole", back_populates="invites")
|
||||
workspace = relationship("Workspace", back_populates="invites")
|
||||
role = relationship("WorkspaceRole", back_populates="invites")
|
||||
created_by = relationship("User", back_populates="created_invites")
|
||||
used_by_memberships = relationship(
|
||||
"SearchSpaceMembership",
|
||||
"WorkspaceMembership",
|
||||
back_populates="invited_by_invite",
|
||||
passive_deletes=True,
|
||||
)
|
||||
|
|
@ -2220,8 +2205,7 @@ class Prompt(BaseModel, TimestampMixin):
|
|||
nullable=False,
|
||||
index=True,
|
||||
)
|
||||
search_space_id = Column(
|
||||
"workspace_id",
|
||||
workspace_id = Column(
|
||||
Integer,
|
||||
ForeignKey("workspaces.id", ondelete="CASCADE"),
|
||||
nullable=True,
|
||||
|
|
@ -2238,7 +2222,7 @@ class Prompt(BaseModel, TimestampMixin):
|
|||
is_public = Column(Boolean, nullable=False, default=False)
|
||||
|
||||
user = relationship("User")
|
||||
search_space = relationship("SearchSpace")
|
||||
workspace = relationship("Workspace")
|
||||
|
||||
|
||||
if config.AUTH_TYPE == "GOOGLE":
|
||||
|
|
@ -2250,7 +2234,7 @@ if config.AUTH_TYPE == "GOOGLE":
|
|||
oauth_accounts: Mapped[list[OAuthAccount]] = relationship(
|
||||
"OAuthAccount", lazy="joined"
|
||||
)
|
||||
search_spaces = relationship("SearchSpace", back_populates="user")
|
||||
workspaces = relationship("Workspace", back_populates="user")
|
||||
notifications = relationship(
|
||||
"Notification",
|
||||
back_populates="user",
|
||||
|
|
@ -2259,13 +2243,13 @@ if config.AUTH_TYPE == "GOOGLE":
|
|||
)
|
||||
|
||||
# RBAC relationships
|
||||
search_space_memberships = relationship(
|
||||
"SearchSpaceMembership",
|
||||
workspace_memberships = relationship(
|
||||
"WorkspaceMembership",
|
||||
back_populates="user",
|
||||
cascade="all, delete-orphan",
|
||||
)
|
||||
created_invites = relationship(
|
||||
"SearchSpaceInvite",
|
||||
"WorkspaceInvite",
|
||||
back_populates="created_by",
|
||||
passive_deletes=True,
|
||||
)
|
||||
|
|
@ -2387,7 +2371,7 @@ if config.AUTH_TYPE == "GOOGLE":
|
|||
else:
|
||||
|
||||
class User(SQLAlchemyBaseUserTableUUID, Base):
|
||||
search_spaces = relationship("SearchSpace", back_populates="user")
|
||||
workspaces = relationship("Workspace", back_populates="user")
|
||||
notifications = relationship(
|
||||
"Notification",
|
||||
back_populates="user",
|
||||
|
|
@ -2396,13 +2380,13 @@ else:
|
|||
)
|
||||
|
||||
# RBAC relationships
|
||||
search_space_memberships = relationship(
|
||||
"SearchSpaceMembership",
|
||||
workspace_memberships = relationship(
|
||||
"WorkspaceMembership",
|
||||
back_populates="user",
|
||||
cascade="all, delete-orphan",
|
||||
)
|
||||
created_invites = relationship(
|
||||
"SearchSpaceInvite",
|
||||
"WorkspaceInvite",
|
||||
back_populates="created_by",
|
||||
passive_deletes=True,
|
||||
)
|
||||
|
|
@ -2550,8 +2534,7 @@ class AgentActionLog(BaseModel):
|
|||
nullable=True,
|
||||
index=True,
|
||||
)
|
||||
search_space_id = Column(
|
||||
"workspace_id",
|
||||
workspace_id = Column(
|
||||
Integer,
|
||||
ForeignKey("workspaces.id", ondelete="CASCADE"),
|
||||
nullable=False,
|
||||
|
|
@ -2622,8 +2605,7 @@ class DocumentRevision(BaseModel):
|
|||
nullable=True,
|
||||
index=True,
|
||||
)
|
||||
search_space_id = Column(
|
||||
"workspace_id",
|
||||
workspace_id = Column(
|
||||
Integer,
|
||||
ForeignKey("workspaces.id", ondelete="CASCADE"),
|
||||
nullable=False,
|
||||
|
|
@ -2664,8 +2646,7 @@ class FolderRevision(BaseModel):
|
|||
nullable=True,
|
||||
index=True,
|
||||
)
|
||||
search_space_id = Column(
|
||||
"workspace_id",
|
||||
workspace_id = Column(
|
||||
Integer,
|
||||
ForeignKey("workspaces.id", ondelete="CASCADE"),
|
||||
nullable=False,
|
||||
|
|
@ -2693,7 +2674,7 @@ class FolderRevision(BaseModel):
|
|||
class AgentPermissionRule(BaseModel):
|
||||
"""Persistent permission rule consumed by :class:`PermissionMiddleware`.
|
||||
|
||||
Scoped at one of: search-space-wide (``user_id`` and ``thread_id`` NULL),
|
||||
Scoped at one of: workspace-wide (``user_id`` and ``thread_id`` NULL),
|
||||
user-wide (``user_id`` set, ``thread_id`` NULL), or per-thread
|
||||
(``thread_id`` set). Loaded at agent build time and converted to
|
||||
:class:`Rule` instances inside the agent factory.
|
||||
|
|
@ -2701,8 +2682,7 @@ class AgentPermissionRule(BaseModel):
|
|||
|
||||
__tablename__ = "agent_permission_rules"
|
||||
|
||||
search_space_id = Column(
|
||||
"workspace_id",
|
||||
workspace_id = Column(
|
||||
Integer,
|
||||
ForeignKey("workspaces.id", ondelete="CASCADE"),
|
||||
nullable=False,
|
||||
|
|
@ -3080,10 +3060,10 @@ def has_all_permissions(
|
|||
def get_default_roles_config() -> list[dict]:
|
||||
"""
|
||||
Get the configuration for default system roles.
|
||||
These roles are created automatically when a search space is created.
|
||||
These roles are created automatically when a workspace is created.
|
||||
|
||||
Only 3 roles are supported:
|
||||
- Owner: Full access to everything (assigned to search space creator)
|
||||
- Owner: Full access to everything (assigned to workspace creator)
|
||||
- Editor: Can create/update content but cannot delete, manage roles, or change settings
|
||||
- Viewer: Read-only access to resources (can add comments)
|
||||
|
||||
|
|
@ -3093,7 +3073,7 @@ def get_default_roles_config() -> list[dict]:
|
|||
return [
|
||||
{
|
||||
"name": "Owner",
|
||||
"description": "Full access to all search space resources and settings",
|
||||
"description": "Full access to all workspace resources and settings",
|
||||
"permissions": DEFAULT_ROLE_PERMISSIONS["Owner"],
|
||||
"is_default": False,
|
||||
"is_system_role": True,
|
||||
|
|
@ -3107,7 +3087,7 @@ def get_default_roles_config() -> list[dict]:
|
|||
},
|
||||
{
|
||||
"name": "Viewer",
|
||||
"description": "Read-only access to search space resources",
|
||||
"description": "Read-only access to workspace resources",
|
||||
"permissions": DEFAULT_ROLE_PERMISSIONS["Viewer"],
|
||||
"is_default": False,
|
||||
"is_system_role": True,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue