Files
speckle-server/packages/server/modules/workspaces/domain/operations.ts
T
Gergő Jedlicska f210d9b749 gergo/web 2109 project region based db connection selector (#3434)
* feat(projects): add project regions, default to null

* feat(multiregion): add projectRegion Db client lookup logic

* feat(multiregion): add project region repositories and caching

* feat(multiRegion): db initialization and get project db client

* feat(docker-compose): add second db for regions testing

* feat(multiRegion): initialize region with pubs and subs working

* fix(multiRegion): get region client even if it was registered in another pod

* feat(workspaces): create workspace resolver split

* feat: update server region metadata

* feat(projects): rewrite project creation

* feat(multiRegion): getRegionDb

* fix(workspaces): get projects now can retur null

* feat(multiRegion): make local multi region DB-s work

* feat: set d efault workspace region

* CR changes

* tests

* feat(multiRegion): bind region properly

* fe update

* test fixes

* feat(multiRegion): automatically create aiven extras plugin

* ci(postgres): use published postgres with aiven extras

* fix(multiRegion): roll back the aiven extras migration, there is a better way

* tests fix

* fix(billing): we do not need to add a seat, if the workspace is on a plan, but has no sub

---------

Co-authored-by: Kristaps Fabians Geikins <fabis94@live.com>
2024-11-06 17:29:08 +01:00

275 lines
6.8 KiB
TypeScript

import { WorkspaceEvents } from '@/modules/workspacesCore/domain/events'
import { StreamRecord } from '@/modules/core/helpers/types'
import {
Workspace,
WorkspaceAcl,
WorkspaceDomain,
WorkspaceRegionAssignment,
WorkspaceWithDomains,
WorkspaceWithOptionalRole
} from '@/modules/workspacesCore/domain/types'
import { EventBusPayloads } from '@/modules/shared/services/eventBus'
import {
MaybeNullOrUndefined,
Nullable,
Optional,
PartialNullable,
StreamRoles,
WorkspaceRoles
} from '@speckle/shared'
import { WorkspaceRoleToDefaultProjectRoleMapping } from '@/modules/workspaces/domain/types'
import { WorkspaceTeam } from '@/modules/workspaces/domain/types'
import { Stream } from '@/modules/core/domain/streams/types'
import { TokenResourceIdentifier } from '@/modules/core/domain/tokens/types'
import { ServerRegion } from '@/modules/multiregion/domain/types'
/** Workspace */
type UpsertWorkspaceArgs = {
workspace: Omit<Workspace, 'domains'>
}
export type UpsertWorkspace = (args: UpsertWorkspaceArgs) => Promise<void>
export type GetUserDiscoverableWorkspaces = (args: {
domains: string[]
userId: string
}) => Promise<
Pick<
Workspace,
'id' | 'name' | 'slug' | 'description' | 'logo' | 'defaultLogoIndex'
>[]
>
export type GetWorkspace = (args: {
workspaceId: string
userId?: string
}) => Promise<WorkspaceWithOptionalRole | null>
export type GetWorkspaceBySlug = (args: {
workspaceSlug: string
userId?: string
}) => Promise<WorkspaceWithOptionalRole | null>
export type GetWorkspaces = (args: {
workspaceIds: string[]
userId?: string
}) => Promise<WorkspaceWithOptionalRole[]>
export type GetWorkspacesBySlug = (args: {
workspaceIds: string[]
userId?: string
}) => Promise<WorkspaceWithOptionalRole[]>
export type StoreWorkspaceDomain = (args: {
workspaceDomain: WorkspaceDomain
}) => Promise<void>
export type GetWorkspaceDomains = (args: {
workspaceIds: string[]
}) => Promise<WorkspaceDomain[]>
type DeleteWorkspaceArgs = {
workspaceId: string
}
export type CountDomainsByWorkspaceId = (args: {
workspaceId: string
}) => Promise<number>
export type DeleteWorkspaceDomain = (args: { id: string }) => Promise<void>
export type GetWorkspaceWithDomains = (args: {
id: string
}) => Promise<WorkspaceWithDomains | null>
export type DeleteWorkspace = (args: DeleteWorkspaceArgs) => Promise<void>
/** Workspace Roles */
export type GetWorkspaceCollaboratorsArgs = {
workspaceId: string
limit: number
cursor?: string
filter?: {
/**
* Optionally filter by workspace role(s)
*/
roles?: string[]
/**
* Optionally filter by user name or email
*/
search?: string
}
}
export type GetWorkspaceCollaborators = (
args: GetWorkspaceCollaboratorsArgs
) => Promise<WorkspaceTeam>
type GetWorkspaceCollaboratorsTotalCountArgs = {
workspaceId: string
}
export type GetWorkspaceCollaboratorsTotalCount = (
args: GetWorkspaceCollaboratorsTotalCountArgs
) => Promise<number>
type DeleteWorkspaceRoleArgs = {
workspaceId: string
userId: string
}
export type DeleteWorkspaceRole = (
args: DeleteWorkspaceRoleArgs
) => Promise<WorkspaceAcl | null>
type GetWorkspaceRolesArgs = {
workspaceId: string
}
/** Get all roles in a given workspaces. */
export type GetWorkspaceRoles = (args: GetWorkspaceRolesArgs) => Promise<WorkspaceAcl[]>
type GetWorkspaceRoleForUserArgs = {
userId: string
workspaceId: string
}
/** Get role for given user in a specific workspace. */
export type GetWorkspaceRoleForUser = (
args: GetWorkspaceRoleForUserArgs
) => Promise<WorkspaceAcl | null>
type GetWorkspaceRolesForUserArgs = {
userId: string
}
type GetWorkspaceRolesForUserOptions = {
/** If provided, limit results to roles in given workspaces. */
workspaceIdFilter?: string[]
}
/** Get roles for given user across several (or all) workspaces. */
export type GetWorkspaceRolesForUser = (
args: GetWorkspaceRolesForUserArgs,
options?: GetWorkspaceRolesForUserOptions
) => Promise<WorkspaceAcl[]>
/** Repository-level change to workspace acl record */
export type UpsertWorkspaceRole = (args: WorkspaceAcl) => Promise<void>
/** Service-level change with protection against invalid role changes */
export type UpdateWorkspaceRole = (
args: Pick<WorkspaceAcl, 'userId' | 'workspaceId' | 'role'> & {
/**
* If this gets triggered from a project role update, we don't want to override that project's role to the default one
*/
skipProjectRoleUpdatesFor?: string[]
/**
* Only add or upgrade role, prevent downgrades
*/
preventRoleDowngrade?: boolean
}
) => Promise<void>
export type GetWorkspaceRoleToDefaultProjectRoleMapping = (args: {
workspaceId: string
}) => Promise<WorkspaceRoleToDefaultProjectRoleMapping>
/** Workspace Projects */
type QueryAllWorkspaceProjectsArgs = {
workspaceId: string
}
export type QueryAllWorkspaceProjects = (
args: QueryAllWorkspaceProjectsArgs
) => AsyncGenerator<StreamRecord[], void, unknown>
/** Workspace Project Roles */
type GrantWorkspaceProjectRolesArgs = {
projectId: string
workspaceId: string
}
export type GrantWorkspaceProjectRoles = (
args: GrantWorkspaceProjectRolesArgs
) => Promise<void>
type UpdateWorkspaceProjectRoleArgs = {
role: {
projectId: string
userId: string
// Undefined or null role means delete role
role?: Nullable<string>
}
updater: {
userId: string
resourceAccessRules: MaybeNullOrUndefined<TokenResourceIdentifier[]>
}
}
export type UpdateWorkspaceProjectRole = (
args: UpdateWorkspaceProjectRoleArgs
) => Promise<Stream | undefined>
/** Events */
export type EmitWorkspaceEvent = <TEvent extends WorkspaceEvents>(args: {
eventName: TEvent
payload: EventBusPayloads[TEvent]
}) => Promise<void>
export type CountProjectsVersionsByWorkspaceId = (args: {
workspaceId: string
}) => Promise<number>
export type CountWorkspaceRoleWithOptionalProjectRole = (args: {
workspaceId: string
workspaceRole: WorkspaceRoles
projectRole?: StreamRoles
skipUserIds?: string[]
}) => Promise<number>
export type GetUserIdsWithRoleInWorkspace = (
args: {
workspaceId: string
workspaceRole: WorkspaceRoles
},
options?: { limit?: number }
) => Promise<string[]>
type WorkspaceUpdateArgs = {
workspaceId: string
workspaceInput: PartialNullable<Omit<Workspace, 'id' | 'createdAt' | 'updatedAt'>>
}
export type UpdateWorkspace = ({
workspaceId,
workspaceInput
}: WorkspaceUpdateArgs) => Promise<Workspace>
/**
* Workspace regions
*/
export type GetAvailableRegions = (params: {
workspaceId: string
}) => Promise<ServerRegion[]>
export type AssignRegion = (params: {
workspaceId: string
regionKey: string
}) => Promise<void>
export type GetDefaultRegion = (params: {
workspaceId: string
}) => Promise<Optional<ServerRegion>>
export type UpsertRegionAssignment = (params: {
workspaceId: string
regionKey: string
}) => Promise<WorkspaceRegionAssignment>