86 lines
2.7 KiB
TypeScript
86 lines
2.7 KiB
TypeScript
import { ProjectEvents } from '@/modules/core/domain/projects/events'
|
|
import { generateProjectName } from '@/modules/core/domain/projects/logic'
|
|
import {
|
|
CreateProject,
|
|
DeleteProject,
|
|
GetProject,
|
|
ProjectVisibility,
|
|
StoreModel,
|
|
StoreProject,
|
|
StoreProjectRole
|
|
} from '@/modules/core/domain/projects/operations'
|
|
import { Project } from '@/modules/core/domain/streams/types'
|
|
import { RegionalProjectCreationError } from '@/modules/core/errors/projects'
|
|
import { StreamNotFoundError } from '@/modules/core/errors/stream'
|
|
import { EventBusEmit } from '@/modules/shared/services/eventBus'
|
|
import { retry } from '@lifeomic/attempt'
|
|
import { Roles } from '@speckle/shared'
|
|
import cryptoRandomString from 'crypto-random-string'
|
|
|
|
export const createNewProjectFactory =
|
|
({
|
|
storeProject,
|
|
getProject,
|
|
deleteProject,
|
|
storeProjectRole,
|
|
storeModel,
|
|
emitEvent
|
|
}: {
|
|
storeProject: StoreProject
|
|
getProject: GetProject
|
|
deleteProject: DeleteProject
|
|
storeProjectRole: StoreProjectRole
|
|
emitEvent: EventBusEmit
|
|
storeModel: StoreModel
|
|
}): CreateProject =>
|
|
async ({ description, name, regionKey, visibility, workspaceId, ownerId }) => {
|
|
const publicVisibilities: ProjectVisibility[] = ['PUBLIC', 'UNLISTED']
|
|
const isPublic = !visibility || publicVisibilities.includes(visibility)
|
|
const isDiscoverable = visibility === 'PUBLIC'
|
|
const project: Project = {
|
|
id: cryptoRandomString({ length: 10 }),
|
|
name: name || generateProjectName(),
|
|
description: description || '',
|
|
isPublic,
|
|
isDiscoverable,
|
|
createdAt: new Date(),
|
|
clonedFrom: null,
|
|
updatedAt: new Date(),
|
|
workspaceId: workspaceId || null,
|
|
regionKey: regionKey || null,
|
|
allowPublicComments: false
|
|
}
|
|
|
|
await storeProject({ project })
|
|
const projectId = project.id
|
|
// if regionKey, we need to make sure it is actually written and synced
|
|
if (regionKey) {
|
|
try {
|
|
await retry(
|
|
async () => {
|
|
const replicatedProject = await getProject({ projectId })
|
|
if (!replicatedProject) throw new StreamNotFoundError()
|
|
},
|
|
{ maxAttempts: 100 }
|
|
)
|
|
} catch (err) {
|
|
if (err instanceof StreamNotFoundError) {
|
|
// delete from region
|
|
await deleteProject({ projectId })
|
|
throw new RegionalProjectCreationError()
|
|
}
|
|
// else throw as is
|
|
throw err
|
|
}
|
|
}
|
|
await storeProjectRole({ projectId, userId: ownerId, role: Roles.Stream.Owner })
|
|
await storeModel({
|
|
name: 'main',
|
|
description: 'default model',
|
|
projectId,
|
|
authorId: ownerId
|
|
})
|
|
await emitEvent({ eventName: ProjectEvents.Created, payload: { project, ownerId } })
|
|
return project
|
|
}
|