Skip to content

msflib.workspaces

Public modules of the msflib-workspaces package.

msflib.workspaces.actions

WorkspaceAction(*, settings: SettingsBase)

Bases: ModelAction[WorkspaceType, WorkspaceCreateType, WorkspaceUpdateType], Generic[WorkspaceType, WorkspaceCreateType, WorkspaceUpdateType]

create_with_owner(session: Session, *, data: WorkspaceCreateType, owner: AccountBase, tenant: TenantBase, update: dict[str, Any] | None = None, commit: bool = True) -> WorkspaceType

For cases where WorkspaceCreateType doesn't include owner_id, this helper creates a workspace and assigns the owner in one step.

resolve_workspace_context(session: Session, *, account: Any, user_action: UserAction) -> dict[str, Any]

Resolve the active workspace context for an account.

Returns a dict with keys: workspaces, current_workspace_id, workspace_id, user_id, user.

UserAction(*, membership_type_resolver: MembershipTypeResolver | None = None)

Bases: ModelAction[UserTypeModel, UserCreateType, UserUpdateType], Generic[UserTypeModel, UserCreateType, UserUpdateType]

Construct a UserAction.

Parameters:

Name Type Description Default
membership_type_resolver MembershipTypeResolver | None

Optional callable with signature (account_id: int, workspace_id: int, owner_id: int) -> Any that returns the membership type to assign. When provided it takes precedence over :meth:resolve_membership_type but can still be beaten by the per-call membership_type argument on :meth:create_membership.

None

resolve_membership_type(*, account_id: int, workspace_id: int, owner_id: int) -> Any

Resolve the membership type for :meth:create_membership.

Resolution priority (highest to lowest):

  1. Per-call membership_type argument on :meth:create_membership.
  2. Constructor-injected membership_type_resolver callable.
  3. Override of this method in a :class:UserAction subclass.
  4. Default enum-introspection logic below (owner → owner, everyone else → member, fallback to schema field default).

Downstream callers should prefer option 2 (constructor injection) for simple policy changes, and option 3 (subclassing) for more complex or advanced membership policies.

msflib.workspaces.config

msflib.workspaces.deps

get_workspace_form_dependencies(*, workspace_create_type: type[Any], workspace_update_type: type[Any]) -> DependencyNamespace

Return reusable FastAPI form dependencies for workspace create/update.

The returned namespace is intentionally mutable so downstream applications can wrap or replace one dependency and inject the namespace back into workspaces.router(...).

msflib.workspaces.eventbus

reset_event_hooks(*, emitter: AppEmitter) -> None

Remove workspace hooks and reset registration state.

This is intended for test isolation when suites intentionally clear global event listeners between tests.

register_event_hooks(*, workspace_action: WorkspaceAction, user_action: UserAction, account_action: AccountAction, emitter: AppEmitter, tenancy_settings: TenancySettings) -> None

Register workspace lifecycle hooks that react to account module events.

Call this once at application startup, after all action instances are configured, to opt the workspace module into the account creation flow.

The registered listener runs within the same database transaction as the triggering AccountAction.create() call (after session.flush(), before session.commit()).

Parameters:

Name Type Description Default
workspace_action WorkspaceAction

A configured WorkspaceAction instance.

required
user_action UserAction

A configured UserAction instance.

required
account_action AccountAction

The application's AccountAction instance used to look up the root/superuser account when setting workspace ownership.

required
tenancy_settings TenancySettings

The app's configured TenancySettings; pass the same instance init_db/request dependencies use so bootstrap resolves the same default tenant row.

required

msflib.workspaces.models

userinfo

User information collection model (feature-flagged).

UserInfoBase

Bases: SchemaBase

Base schema for user information.

UserInfo

Bases: ModelBase

Non-table fallback when feature flag is disabled.

UserInfoCreate

Bases: UserInfoBase

Create schema for user information.

UserInfoUpdate

Bases: UserInfoBase

Update schema for user information.

UserInfoRead

Bases: ModelBase

Read schema for user information.

workspace_user

Schemas and models for workspace membership and joining.

WorkspaceJoinBase

Bases: SchemaBase

Schema for joining a workspace.

WorkspaceSwitchBase

Bases: SchemaBase

Schema for switching to a different workspace.

UserReadWithWorkspaceSlug

Bases: UserRead

User read schema with workspace slug included.

msflib.workspaces.router

router(*, get_session: Callable, get_current_account: Callable, get_current_account_or_none: Callable, role_check: Callable, settings: SettingsBase, account_type: type[AccountBase] = AccountBase, workspace_type: type[WorkspaceBase] = WorkspaceBase, user_type: type[UserBase] = UserBase, workspace_create_type: type[Any] | None = None, workspace_update_type: type[Any] | None = None, workspace_form_dependencies: DependencyNamespace | None = None, workspace_action: WorkspaceAction | None = None, user_action: UserAction | None = None, get_current_tenant: Callable | None = None, prefix: str = '/workspaces', tags: list[str] | None = None) -> APIRouter

Create the workspace router.

Downstream applications may override the default multipart/form-data processors by passing workspace_form_dependencies from msflib.workspaces.get_workspace_form_dependencies(...).

get_current_tenant: resolved once at the endpoint boundary, the same way documents.router's get_current_tenant is (see msflib.tenancy.deps.get_tenant_dependencies) -- yields a Tenant row. When omitted, workspace creation falls back to resolve_default_tenant_id(create_if_missing=False) (today's single-tenant resolution) and raises a 500 if the default tenant hasn't been seeded yet, matching get_tenant_dependencies's own fail-loud convention instead of silently inserting one as a side effect of the request.

user_profile_router(*, get_session: Callable, get_current_account: Callable, get_current_active_account: Callable, get_current_workspace: Callable, settings: SettingsBase, profile_type: type[ProfileBase], account_type: type[AccountBase], user_type: type[UserBase] = UserBase, profile_read_type: type[ProfileRead] = ProfileRead, profile_action: ProfileAction | None = None, account_action: AccountAction | None = None, user_action: UserAction | None = None, profile_create_type: type[Any] | None = None, profile_update_type: type[Any] | None = None, profile_decorator: UserProfileDecorator = lambda session, profile, workspace: profile, prefix: str = '/{workspace_slug}/profiles', tags: list[str] | None = None) -> APIRouter

Create a workspace-aware profile router.

Mirrors account.profile_router but every endpoint resolves the current workspace via get_current_workspace and enforces workspace membership. The profile_decorator receives (session, profile, workspace) so callers can enrich the response with workspace-specific data.

Parameters:

Name Type Description Default
get_session Callable

Dependency that yields a DB session.

required
get_current_account Callable

Dependency that returns the authenticated account.

required
get_current_active_account Callable

Dependency that returns the active account.

required
get_current_workspace Callable

Dependency that resolves the current workspace.

required
settings SettingsBase

Application settings.

required
profile_type type[ProfileBase]

Concrete Profile model class.

required
account_type type[AccountBase]

Concrete Account model class.

required
user_type type[UserBase]

Concrete User (membership) model class.

UserBase
profile_read_type type[ProfileRead]

Response schema for profile endpoints.

ProfileRead
profile_action ProfileAction | None

Optional pre-built ProfileAction instance.

None
account_action AccountAction | None

Optional pre-built AccountAction instance.

None
user_action UserAction | None

Optional pre-built UserAction instance.

None
profile_decorator UserProfileDecorator

Callable (session, profile, workspace) -> Any applied to every profile before it is returned.

lambda session, profile, workspace: profile
prefix str

URL prefix (default includes {workspace_slug} path param).

'/{workspace_slug}/profiles'
tags list[str] | None

OpenAPI tags.

None

user_me_router(*, get_session: Callable, get_current_account: Callable, get_current_active_account: Callable, get_current_workspace: Callable, user_type: type[UserBase], user_read_type: type[UserRead] = UserRead, user_action: UserAction | None = None, prefix: str = '/{workspace_slug}/users', tags: list[str] | None = None) -> APIRouter

Create workspace-user read endpoints scoped by workspace slug.